【问题标题】:Use "Stream-like" Input to C++ function对 C++ 函数使用“类流”输入
【发布时间】:2014-02-04 01:26:54
【问题描述】:

我知道可以使用预处理器宏来创建一个接受“类流”输入的函数。为了澄清我所说的“类流”输入是什么意思,让我举个例子(LOGGER的输入是“类流”):

#include <iostream>
#include <sstream>

#define LOGGER(streamText) {   \
    std::ostringstream buffer; \
    buffer << streamText;      \
    /* Some processing */      \
    std::cout << buffer.str() << std::endl; \
}

int main(){
    LOGGER("Foo: " << "Bar!: " << 42);
}

这个输出:

Foo:酒吧!:42

我想为一个普通的 C++ 函数提供一个类似的接口。有点像这样(不编译,不是有效的 C++ 代码):

// has:
//    - insert( std::ostringstream & str ) function for obtaining content of a std::ostringstream
//    - formatting functions
//    - print( std::ostream & str ) function
class logger_class;

logger_class logger_function( some_magic_type varName ){
    std::ostringstream & str = varName;
    logger_class log;
    log.insert( str );
    return log;
}

int main(){
    logger_class log = logger_function("Foo: " << "Bar!: " << 42);
    log.format( some_formatting_options );
    log.print( std::cout );
}

这将允许在将输出实际发送到 std::cout 之前对其进行格式化。

编辑: C++11 和 boost 解决方案也是允许的。

【问题讨论】:

  • 您是否正在寻找
  • @urzeit 之类的。我想确保记录器可以假设他刚才传递的输入是完整的消息。让我举个例子:一个格式化选项是着色,它(假设是 ANSI 终端)由两个分隔符包围内容组成。通过使用宏解决方案,这可以通过在将日志消息流式传输到输出流之前和之后添加分隔符来轻松完成(因为整个日志消息都包含在宏的参数中)。
  • 我希望函数返回记录器对象,因为这允许通过使用方法链接设置格式选项,即:logger_function("Foo" &lt;&lt; 42).log_level( 500 ).color( RED ).weight( BOLD ).end_line();
  • 您似乎混合了两种风格:方法链接和流式处理(通常使用操纵器而不是方法调用)。例如,这种语法是否有效:log() &lt;&lt; "Foo" &lt;&lt; 42 &lt;&lt; log_level(500) &lt;&lt; log_color(RED) &lt;&lt; log_weight(BOLD) &lt;&lt; endl; ?
  • 为了使用流媒体实现着色,只需编写:log() &lt;&lt; log_level( 500 ) &lt;&lt; log_color(RED) &lt;&lt; log_weight(BOLD) &lt;&lt; "Foo" &lt;&lt; 42 &lt;&lt; finish_color() &lt;&lt; finish_weight() &lt;&lt; std::endl;,因为 ANSI 着色需要开始着色结束着色序列。

标签: c++ stream stringstream


【解决方案1】:

使用 C++11,您可以使用可变参数模板:

template <typename T>
std::ostringstream & fill_stream(std::ostringstream & str, T&& t)
{
    return (str << std::forward<T>(t));
}

template <typename T, typename... Vs>
std::ostringstream & fill_stream(std::ostringstream & str, T&& t, Vs&&... vs)
{
    str << std::forward<T>(t);
    return fill_stream(std::forward<Vs>(vs)...);
}

template <typename... Ts>
logger_class logger_function( Ts&&... vars ){
    std::ostringstream & str;

    if (!fill_stream(str, std::forward<Ts>(vars)...))
    {
        //Error!
    }

    logger_class log;
    log.insert( str );
    return log;
}

然后:

int main()
{
    logger_class log = logger_function("Foo: ", "Bar!: ", 42);
    log.format( some_formatting_options );
    log.print( std::cout );
}

如果您想避免立即创建字符串流,您可以创建一个模板类,将其参数存储在一个元组中。

template <typename... Ts>
logger_class<Ts&&...> logger_function( Ts&&... vars ){
    // logger_class should probably store its arguments as a tuple
    logger_class<Ts&&...> log ( std::forward<Ts>(vars)... );
    return log;
}

int main()
{
    auto log = logger_function("Foo: ", "Bar!: ", 42);
    log.format( some_formatting_options );
    log.print( std::cout );
}

【讨论】:

    猜你喜欢
    • 2020-08-15
    • 1970-01-01
    • 2012-02-27
    • 2010-09-29
    • 2010-11-04
    • 1970-01-01
    • 1970-01-01
    • 2011-12-28
    • 2022-11-21
    相关资源
    最近更新 更多