C++传递格式化字符串作为函数参数

3

好的,这个问题实际上不应该很难解决,但是尝试了几次后,我没有找到任何解决方案。

如何在一行中将格式化字符串传递给函数? 我想要一个简单的方法,可以用于日志记录/调试等目的,类似于以下内容:

void debug(string s){
    if (DEBUG) cerr << s;
}

我希望能够向此函数发送格式化的字符串,例如:
debug("reading %s" % fname);

我的主要目标是尽可能多地将功能放在调试方法中,以便每当我想将东西写入stderr时,能够使生活更加轻松。

printf解决方案似乎需要大量代码来进行简单的格式化,并且boost :: format似乎返回一些模糊的类型,如果不始终包括一些.str()内容,则无法轻松地用作参数。

我是不是太懒了,不适合成为C ++程序员,还是有一种巧妙的方法来实现这个目标,我还没有发现?


1
在我看来...太懒了...;) 这是C++的方式,使用boost::format的C风格printf是一个选择。另一个就是简单地使用“+”将它们连接起来(如果至少有一个是std :: string)。 - Adriano Repetti
1
在决定是否打开DEBUG标志并且确实需要打印输出时,您不希望创建字符串(代价昂贵)。 - jsantander
3个回答

5
您可以使用__VA_ARGS__定义围绕fprintf的宏:
#define DBGLOG(format, ...) if(DEBUG){ fprintf(stderr, "%s -- %d -- ", __FUNCTION__, __LINE__); fprintf(stderr, format, ##__VA_ARGS__);}

如果 DEBUG 为真,则会输出函数名和行号,然后是您想要打印的任何内容。
例如:
DBGLOG("%d\n", some_integer);

这将在整数值之前添加函数和行号,并将其打印出来。

如果我可以建议,使用\来将宏拆分成多行,使其更易读。 - jsantander
这在编译时给我一个警告:“无法通过'...'传递非POD类型的对象'struct std :: string'; 调用将在运行时中止”,并且在运行时确实如此:“非法指令”。 - niefpaarschoenen
你不能将std::string传递给fprintf,它需要一个C字符串。如果你有一个std::string S,那么你必须传入S.c_str()到fprintf中才能打印它。例如: std::string S = "asdf"; DBGLOG("%s\n", S.c_str()); - user3736255
好的,那么相比其他建议的解决方案,这个有什么额外的优势呢? - niefpaarschoenen
好的一面是:这将在C和C++下编译(其他解决方案仅适用于C++),它将更快,需要更少的代码来生成输出,并且更容易格式化参数。坏的一面是:可变参数列表没有安全性(编译器通常会发出警告,但如果参数列表与格式字符串不匹配仍会编译),并且不可扩展。 - user3736255

1
你可以编写一个函数,接收格式并将其传递给其他函数:
void debug( std::string s )
{
    if (DEBUG) cerr << s; 
}

void debug( boost::format format )
{
     debug( format.str() );
}

0

这里的普通C++解决方案有点不同:您的debug函数应该返回一个包装器,围绕std::cerr(或任何其他输出流)进行操作,类似于:

class OStreamWrapper
{
    std::ostream* myStream;
public:
    OStreamWrapper( std::ostream* init ) : myStream( init ) {}
    template <typename T>
    OStreamWrapper& operator<<( T const& value )
    {
        if ( myStream != nullptr ) {
            *myStream << value;
        }
    }
};

OStreamWrapper
debug()
{
    return OStreamWrapper( DEBUG ? &std::cerr : nullptr );
}

然后你可以使用它:

debug() << "reading " << fname << '\n';

这样做的额外优点是,除非调试处于活动状态,否则不会执行必要的实际转换以格式化输出。


但是你无法避免评估不同的组件(在 << 之间)。 - jsantander
1
@jsantander 不是,但它们通常只是用于这种情况的变量。(还有更复杂的解决方案可以避免它。) - James Kanze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接