如何编写不带参数包的可变参数函数?

时间:2018-07-13 19:27:33

标签: c++ c++11 templates variadic-templates template-meta-programming

假设我有一个模板

template<typename Bar>
Result foo(const Input& input);

而我想创建一个模板foo(),该模板将获得许多Bar模板参数和许多Input,并将Result放在一起。

我写了一个带有输入容器的版本:

template<typename Bar>
Result foo(const std::vector<Input>& inputs);

template<typename Bar1, typename Bar2, typename ... Bars>
Result foo(const std::vector<Input>& inputs) {
    // calls foo<Bar2, Bars ...>(shorter_inputs);
}

但是,如果输入的长度与模板参数的数量匹配,则上述版本无法在编译时检查。另外,我想要一个只需要输入内容而不需要容器的版本:

foo<Bar1, Bar2>(input1, input2);
// instead of
// foo<Bar1, Bar2>({input1, input2});

我试图写这样的东西

template<typename Bar1, typename Bar2, typename ... Bars>
Result bar(const Input& in1, const Input& in2, const Input& ... inputs)

被编译器拒绝,因为...仅适用于参数包。是否可以在不使用va_args的情况下用C ++编写这样的可变参数函数?

2 个答案:

答案 0 :(得分:3)

只需使用两个参数包:

EthernetServer ArduinoTcpServer(22);

答案 1 :(得分:1)

不确定要了解什么...

如果ResultInput是类型而不是模板参数,并且您希望模板foo()可以接收多达Input个对象作为模板参数,则可以从自定义模板参数GetFirst,以选择可变参数列表中的第一个模板参数

template <typename T0, typename ...>
struct GetFirst
 { using type = T0; };

并按如下所示编写foo()

template <typename ... Bars>
Result foo (typename GetFirst<Input, Bars>::type const & ... is)
 { 
   // something with is...
   return {};
 }

所以你有

//foo<long, long long>(Input{}, Input{}, Input{}); // compilation error

foo<int, long, long long>(Input{}, Input{}, Input{}); // compiles

//foo<int, long, long long>(Input{}, Input{}); // compilation error

如果您要递归管理单个is...,则可以按以下方式编写foo()

template <typename, typename ... Bars>
Result foo (Input const & i0,
            typename GetFirst<Input, Bars>::type const & ... is)
 {
   // do something with i0

   return foo<Bars...>(is...);
 }

,但是您还需要一个基础案例模板foo()来终止递归;我建议一个foo()接收一个带有默认值的模板非类型参数(以在列表为空时拦截Bars...

template <int = 0>
Result foo ()
 { return {}; }

以下是一个完整的,也许很愚蠢的但编译示例

struct Input  { };
struct Result { };

template <typename T0, typename ...>
struct GetFirst
 { using type = T0; };

// ground case
template <int = 0>
Result foo ()
 { return {}; }

// recursive case
template <typename, typename ... Bars>
Result foo (Input const & i0,
            typename GetFirst<Input, Bars>::type const & ... is)
 {
   // do something with i0

   return foo<Bars...>(is...);
 }

int main()
 {
   //foo<long, long long>(Input{}, Input{}, Input{}); // compilation error

   foo<int, long, long long>(Input{}, Input{}, Input{}); // compiles

   //foo<int, long, long long>(Input{}, Input{}); // compilation error
 }