可变宏:无法通过“...”传递非平凡可复制类型的对象

ene*_*ski 2 c++ macros variadic-macros

我正在尝试为日志记录机制编写一个宏。我写了一个可变参数宏,但它不适用于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;
}
Run Code Online (Sandbox Code Playgroud)

如果我像下面这样调用宏,我不会得到任何错误。

LOG_NOTE("%s %d %s", "Hello World", bar, "random string");
Run Code Online (Sandbox Code Playgroud)

编译器输出:

在函数“int main()”中:5:49:错误:无法通过“...”11:5 传递非平凡可复制类型“std::string {aka class std::basic_string}”的对象:注意: 在宏 'LOG_NOTE' 的扩展中

lub*_*bgr 5

这里的问题不是可变参数宏,而是对printf. 查看文档:格式说明符"%s"对应于char*,而不是std::stringprintf只能处理原始内置类型。您可以将调用更改为

LOG_NOTE("%s %d %s", "Hello World", bar, foo.c_str());
Run Code Online (Sandbox Code Playgroud)

来解决这个问题。


Ric*_*ges 5

我写了一个可变参数宏

别。使用可变参数模板函数。

您遇到的实际问题是您试图std::string通过 C API ( printf)传递 C++ 对象( )。这不可能。

您需要一些转换机制,例如:

#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;
}
Run Code Online (Sandbox Code Playgroud)

示例输出:

Hello World 5 random string
Run Code Online (Sandbox Code Playgroud)

http://coliru.stacked-crooked.com/a/beb3431114833860

更新:

对于 C++11,您需要手动拼出返回类型:

#include <stdio.h>
#include <string>

template<class T>
T const& convert_for_log_note(T const& x)
{
    return x;
}

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;
}
Run Code Online (Sandbox Code Playgroud)