1

这是一个打印参数的可变参数模板。

#include <string>
#include <iostream>

void Output() {
    std::cout<<std::endl;
}

template<typename First, typename ... Strings>
void Output(First arg, const Strings&... rest) {
    std::cout<<arg<<" ";
    Output(rest...);
}

int main() {
    Output("I","am","a","sentence");
    Output("Let's","try",1,"or",2,"digits");
    Output(); //<- I do not want this to compile, but it does.

    return 0;
}

有没有办法在没有“无参数”调用工作的情况下获得此功能,并且不必每次都编写两个函数?

4

3 回答 3

3

您可能希望保持第一个参数和其余参数的分离,您可以使用:

template<typename First, typename ... Rest>
void Output(First&& first, Rest&&... rest) {
    std::cout << std::forward<First>(first);
    int sink[]{(std::cout<<" "<<std::forward<Rest>(rest),0)... };
    (void)sink; // silence "unused variable" warning
    std::cout << std::endl;
}

请注意,我使用完美转发来避免复制任何参数。以上具有避免递归的额外好处,因此可能会产生更好(更快)的代码。

我编写的方式sink还保证了rest从左到右扩展的表达式被评估 - 与仅编写辅助函数的天真的方法相比,这很重要template<typename...Args>void sink(Args&&...){}

活生生的例子

于 2013-10-27T07:11:20.740 回答
2

从转发类型函数调用该函数并具有这样的 static_assert :

template <typename ... Args>                                                       
void forwarder(Args ... args) {                                                    
    static_assert(sizeof...(args),"too small");                                    
    Output(args...);                                                               
}  
于 2013-10-27T04:01:31.567 回答
2

据我所知,有两个问题:

  1. 如何避免Output()没有参数的调用。
  2. 有没有更简单的方法来结束编译时递归?

我对第 1 项的解决方案如下:

template<typename T>
void Output(const T & string) {
    std::cout<<string<<std::endl;
}

template<typename First, typename ... Strings>
void Output(const First & arg, const Strings & ... rest) {
    std::cout<<arg<<" ";
    Output(rest...);
}

基本上,不是在模板列表为空时结束递归,而是在它只包含一种类型时结束它。上面和问题中的代码有一个区别:如果在最后一项之后不输出任何空格。相反,它只是输出换行符。

对于第二个问题,请参见上面 Daniel Frey 的答案。我真的很喜欢这个解决方案,虽然花了一些时间来掌握它(我赞成这个答案)。同时我发现它使代码更难阅读/理解,因此更难维护。目前,除了小的个人代码片段外,我不会使用该解决方案。

于 2013-10-27T12:32:52.710 回答