C++ Fixed-size general-purpose thread pool
Ensure the mutex is locked when changing should_terminate_m

In the destructor, you should hold the mutex locked while changing should_terminate_m. It may work as it is in this particular case, but in general, if you hold a mutex while accessing a variable anywhere in the code (it's held in thread_loop() while reading it), you should hold the mutex everywhere you access it. This avoids unexpected behavior.

Stick with either std::unique_lock or std::scoped_lock

You use both types of locks in the code. While functionally it should be perfectly fine, it's weird to mix these two. Be consistent and use only one of them. I recommend sticking with std::scoped_lock if you don't mind not being compatible with pre-C++17 compilers.

Issues with wait()

One issue I see is that in order to support the wait() member function, you have a reference counter busy_m, and you have to notify the condition vairable pool_cv_m every time a task finishes. This adds overhead even if nothing is actually calling wait(), but more importantly, because you use main_thread_cv.notify_one(), if multiple threads are calling wait(), then the notification might go to the wrong thread.

Another issue is that if jobs are enqueued often enough that the queue is never empty, wait() never returns, even though all jobs that were enqueued before wait() was called did finish.

You could indeed make it explicit that only the main thread is allowed to enqueue jobs and call wait(), but that might limit the usefulness of this thread pool somewhat.