В основном коде при старте вызываем
gsbutils::DDebug::init(0, NULL); // или gsbutils::DDebug::init(1, (const char*)"logname");
gsbutils::DDebug::set_debug_level(7);
gsbutils::DDebug::set_flag(1);
где 0 - вывод в консоль, 1 - вывод в syslog (local7.log).
Если вывод в syslog, "logname" - имя процесса в логе. При выводе в консоль параметр игнорируется.
По окончании закрываем лог и поток.
gsbutils::DDebug::stop();
std::string f(std::string_view runtime_format_string)
{
// return std::format(runtime_format_string, "foo", "bar"); // error
return std::vformat(runtime_format_string, std::make_format_args("foo", "bar")); // OK
}
Wait сначала проверяет предикат (если он есть), а потом уже снимает блокировку и начинает принимать уведомления, усыпляя поток. Причём, делает это фактически атомарно (т.е. между снятием блокировки и началом приёма уведомлений другой поток вклиниться не может – это тоже важно). После пробуждения устанавливает блокировку обратно (здесь тоже обычно есть оптимизация, из-за которой рекомендуют notify ставить перед unlock'ом) и снова идёт на проверку предиката.
Если предикат есть и возвращает true, никаких unlock'ов не будет.
Спецификаторы определения — слова typedef, inline, friend, constexpr, constinit, register, static, thread_local, extern, mutable. Спецификаторы типа — что угодно, что полностью определяет тип: начиная от int и заканчивая vector::const_iterator. Модификаторы типа — слова short, long, signed, unsigned. Квалификаторы — слова const, volatile. Спецификаторы доступа — слова private, protected, public. Идентификатор — имя объекта, подчиняющееся определённым правилам. Объявитель — это часть объявления переменной или функции, и если ты не лезешь с головой в тонкости синтаксиса Си, тебе не надо. Инициализатор — это int i = 1 или int i {1}.