我正在尝试为日志记录机制编写宏。我编写了一个可变参数宏,但不适用于std::string
。该代码如下所示:
#include <stdio.h>
#include <string>
#define LOG_NOTE(m, ...) printf(m, ##__VA_ARGS__)
int main()
{
std::string foo = "random string";
int bar = 5;
LOG_NOTE("%s %d %s", "Hello World", bar, foo);
return 0;
}
如果我按如下所示调用宏,则不会出现任何错误。
LOG_NOTE("%s %d %s", "Hello World", bar, "random string");
编译器输出:
在函数'int main()'中:5:49:错误:无法传递以下对象 非平凡类型'std :: string {aka class std :: basic_string}'到'...'11:5:注意:扩展 宏“ LOG_NOTE”
答案 0 :(得分:3)
这里的问题不是可变参数宏,而是对printf
的调用。看一下documentation:格式说明符"%s"
对应于char*
,而不是std::string
。 printf
仅能处理原始的内置类型。您可以将调用更改为
LOG_NOTE("%s %d %s", "Hello World", bar, foo.c_str());
要解决此问题。
答案 1 :(得分:3)
您无法将对象传递给printf
,因此您当前必须使用
LOG_NOTE("%s %d %s", "Hello World", bar, foo.c_str());
如果不需要格式化,只写每个用空格隔开的参数,则可以简单地使用可变参数模板而不是MACRO:
template <typename ... Ts>
void LOG_NOTE(const Ts&...args)
{
const char* sep = "";
(((std::cout << sep << args), sep = " "), ...); // C++17 folding expression
// C++11/C++14 version are more verbose:
// int dummy[] = {0, ((std::cout << sep << args), (sep = " "), 0)...};
// static_cast<void>(dummy); // avoid warning for unused variable
}
int main()
{
std::string foo = "random string";
int bar = 5;
LOG_NOTE("Hello World", bar, foo);
}
答案 2 :(得分:2)
我写了一个可变参数宏
不要。使用可变参数模板功能。
您遇到的实际问题是,您试图通过C API(std::string
)传递C ++对象(printf
)。这是不可能的。
您需要某种转换机制,例如:
#include <stdio.h>
#include <string>
template<class T>
decltype(auto) convert_for_log_note(T const& x)
{
return x;
}
decltype(auto) convert_for_log_note(std::string const& x)
{
return x.c_str();
}
template<class...Args>
void LOG_NOTE(const char* format, Args&&...args)
{
printf(format, convert_for_log_note(args)...);
}
int main()
{
std::string foo = "random string";
int bar = 5;
LOG_NOTE("%s %d %s\n", "Hello World", bar, foo);
return 0;
}
示例输出:
Hello World 5 random string
答案 3 :(得分:0)
我无法获得@richardhodges好的解决方案,无法在我尝试过的任何C ++ 11编译器中工作。但是,以下方法适用于gcc -std=c++11
:
#include <stdio.h>
#include <string>
template<class T>
T convert_for_log_note(T const& x)
{
return x;
}
inline const char* convert_for_log_note(std::string const& x)
{
return x.c_str();
}
template<class...Args>
void LOG_NOTE(const char* format, Args&&...args)
{
printf(format, convert_for_log_note(args)...);
}
int main()
{
std::string foo = "random string";
int bar = 5;
LOG_NOTE("%s %d %s\n", "Hello World", bar, foo);
return 0;
}
在上述解决方案中,对于Arduino C ++编译器,关键字inline
是必需的,而其他g ++编译器则不需要(无论如何,我已经尝试过了)。如果没有此关键字,则将编译Arduino代码,但是链接器会抱怨多个定义。