C — vsprintf_s и std::string?

#c #stdstring

#c #stdstring

Вопрос:

У меня есть функция ведения журнала, которая использует параметры ‘…’ и создает конечную выходную строку с помощью vsprintf_s

это работает нормально, за исключением того, что мне всегда приходится использовать c_str () для печати строк

сначала я думал, что это не проблема, но добавлять все эти .c_str() после каждой строковой переменной довольно сложно, пока я продолжаю их забывать

Хотя, возможно, гуру C мог бы просветить меня по этому вопросу, есть ли способ заставить мою функцию ведения журнала позаботиться об этом самостоятельно?

 void Logger::print(const std::string fmt, ...)
{
    va_list args;
    int len;
    char * buffer;
    va_start(args, fmt);
    len = _vscprintf(fmt.c_str(), args) 1;
    buffer = (char*)malloc(len * sizeof(char));
    vsprintf_s(buffer, len, fmt.c_str(), args);
    va_end(args);
    std::cout << buffer << std::endl; 
    free(buffer);
}
  

Спасибо

Комментарии:

1. Я говорю не о формате, а о параметрах, очевидно, поскольку я упомянул, что мне пришлось добавить .c_str()

2. Как насчет чего-нибудь радикально смелого и свежего, например, вообще не использовать printf семейство функций?

3. лол, лучшая за день 🙂

Ответ №1:

Вы можете добавить два шаблона функции-оболочки с переменными значениями, подобных этому:

 #include <type_traits>

template <class Arg>
decltype(auto) prepare(const Argamp; arg)
{
   if constexpr (std::is_same_v<Arg, std::string>)
      return arg.c_str();
   else
      return arg;
}

template <class ...Args>
void printWrapper(Argsamp;amp;... args)
{
   Log::print(prepare(std::forward<Args>(args))...);
}
  

и вызывать printWrapper вместо исходной функции-члена. Обратите внимание, что я предположил, что Log::print здесь является статической функцией-членом. Если это не так, вам нужно это скорректировать. Теперь это должно сработать:

 const std::string hello("hello");

printWrapper("%d %s %s", 42, hello, "world");
  

Обратите внимание, что для компиляции этого требуется C 17.

Комментарии:

1. Вы отключили все полезные предупреждения, которые современный компилятор мог бы выдавать для строк неправильного формата.

2. @n.m. Да, я согласен с этой проблемой.

3. значит, это не очень хорошая идея? Я не вижу никакой отключающей прагмы… Я попробую

4. @user7082181 это не явное «отключение», а подразумеваемое. Чтобы предупреждение сработало, компилятор должен увидеть строковый литерал исходного формата: printf("%s", 3) будет предупреждать, const char* fmt = "%s"; printf(fmt, 3); не будет выдавать предупреждения в последних версиях clang и gcc