如何编写不能接受零参数的可变参数模板?

时间:2013-10-27 00:57:50

标签: function templates c++11 parameters variadic-templates

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

#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;
}

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

3 个答案:

答案 0 :(得分: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扩展的表达式从左到右进行评估 - 与仅仅编写辅助函数的天真方法相比,这很重要{{1 }}

Live example

答案 1 :(得分:2)

从转发类型函数调用该函数,并具有如下的static_assert:

template <typename ... Args>                                                       
void forwarder(Args ... args) {                                                    
    static_assert(sizeof...(args),"too small");                                    
    Output(args...);                                                               
}  

答案 2 :(得分:2)

据我所知,有两个任务:

  1. 如何避免没有参数的Output()来电。
  2. 是否有更简单的方法来结束编译时间递归?
  3. 我对第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的回答。我真的很喜欢这个解决方案,虽然花了一些时间来掌握它(我赞成了答案)。与此同时,我发现它使代码更难以阅读/理解,因此难以维护。目前我不会在任何小型个人代码片段中使用该解决方案。