【问题标题】:Print using C++ variadic template使用 C++ 可变参数模板打印
【发布时间】:2013-06-04 13:54:05
【问题描述】:

我完成了我必须以 C# 样式进行打印的任务

tprintf("{} world{} {} {} {}\n","Hello",'!',123," Je", "end");

代码如下

void tprintf(const char* format) // base function
{
    std::cout << format;
}

template<typename T, typename... Targs>
void tprintf(const char* format, T value, Targs... Fargs)
{
    for ( ; *format != '\0'; format++ ) {
           if(*format == '{'){
                if(format[1] == '}'){
           std::cout << value;
           tprintf(format+2, Fargs...); // recursive call
           return;
           }
        }
        std::cout << *format;
    }
}

现在我必须做一些不同的事情:

tprintf("{1} {3} + {2} = {4} {1}.", "11", 7.5 , 4, 11.5);

输出:

11 4 + 7.5 = 11.5 11.

所以我认为在这里对 args 进行简单的递归迭代是行不通的。我必须知道所有起作用的参数。我想我应该做的是开始将所有参数放入数组中,然后将它们输入到模式字符串中的正确位置。但是怎么做呢?

我做了这个

template<typename... Args> inline string pass(Args&&...) {return "End";}

template<typename T>
string some_function(T a){
    std::ostringstream ostr;
    ostr << a;
    //cout<<ostr.str();
    return ostr.str();
}

  template<typename... Args> inline void expand(Args&&... args) {
    string a="";
        
    a.append(pass( some_function(args)... ))<<endl;

    cout<<" result "<<a<<endl;
  }

struct pass {
    template<typename ...T> pass(T...) {}
  };

但这只会返回“结束”。我意识到这种行为的原因与哪个模板行为和递归有关。递归调用的最后一个想法是 template inline string pass(Args&&...) {return "End";} 所以我展开函数我只得到 End string 而不是一个字符串,包括所有解析为字符串的 args。

所以我的问题是如何使这个功能正常工作

tprintf("{1} {3} + {2} = {4} {1}.", "", 7.5 , 4, 11.5);

【问题讨论】:

    标签: c++ loops printf variadic-templates


    【解决方案1】:

    你最终会得到类似的东西:

    a.append(pass("7.5"), pass("4"), pass("11.5"))

    将“结束”附加到 a。

    首先,很明显,cout 不会在这里接受你的“数组”,即使你实际上给了它一个数组。你需要一个一个输出参数。所以你必须通过递归来提取每一个。

    【讨论】:

    • 但是当我有更多或更少的参数时我该怎么办?
    【解决方案2】:

    您可以使用 lambda 函数。

    template< typename ... args >
    void tprintf( char const * fmt, args const & ... a ) {
        std::array< std::function< void() >, sizeof ... (a) > fmt_fun
            = { [&a]{ std::cout << a; } ... };
    
        for ( ; * fmt; ++ fmt ) {
            ...
            std::size_t fmt_n = * fmt - '0';
            fmt_fun[ fmt_n ](); // print nth argument
            ...
        }
    }
    

    请注意,不需要元编程风格的递归包迭代。

    嗯,这个 code works in Clang 但在 GCC 中与 longstanding bug 发生冲突。

    【讨论】:

    • 但是我得到了一些错误:参数包没有用'...'扩展:|在这一行 "= { [&a]{ std::cout
    • @Aku 你在使用 GCC 吗?此外,只是说... 的行是伪代码。你应该用你的 {x} 解析替换它。我使用 Clang 对其进行了测试,唯一的变化是删除了 ... 行,并将 tprintf( "021", "Hel", "rld!\n", "lo, wo" ); 转换为 Hello, world!
    • 不应该是sizeof...(a)sizeof(args)
    • @0x499602D2 aargs 都是参数包,所以 sizeof ... (args) 也可以工作。但我对包的长度感兴趣,即sizeof ...,而不是普通类型的字节数sizeof
    猜你喜欢
    • 1970-01-01
    • 2021-05-19
    • 2022-01-14
    • 2022-01-06
    • 2012-09-02
    • 1970-01-01
    • 2022-01-23
    • 2021-05-23
    相关资源
    最近更新 更多