为什么在迭代可变参数模板参数时我们必须使用额外的构造?

Ale*_*lex 3 c++ variadic-templates c++11 c++14 c++17

为什么在迭代可变参数模板参数时我们必须使用其他构造,如(non()- function,temp[]- array或empty [](...){}- lambda)?

众所周知,我们可以使用以下方法在C++中使用可变参数模板迭代参数包:

http://ideone.com/GXDPDw

#include <iostream>
#include <cstdlib>
#include <valarray>
#include <numeric>
using namespace std;

template<typename ...Args> constexpr inline void non(Args ...) {}

template<typename T, typename ...Args>
inline T sum1(T val, Args ...args) { non(val += args ...); return val; }   // v1
// why do we need some function non() here?

template<typename T, typename ...Args>
inline T sum2(T val, Args ...args) { auto tmp = { val += args... }; return val; }   // v2
// why do we need some array tmp[] here?

template<typename T, typename ...Args>
inline T sum3(T val, Args ...args) { [](...){}((val += args)... ); return val; }   // v3
// why do we need empty lambda [](...){} here?

template<typename T, typename ...Args>
inline T sum4(T val, Args ...args) { for(auto &i:{ args... }) val += i; return val; }//v4

template<typename ...Args, typename T = common_type_t<Args...>>
inline T sum5(Args ...args) { return std::valarray<T>({ args... }).sum(); }   // v5


template<typename T> constexpr inline T sum6(T val) { return val; }

template<typename T, typename ...Args>
constexpr inline T sum6(T val, Args ...args) { return val + sum6(args...); }  // v6


int main() {    
    cout << sum1(1, 2, 3) << endl;
    cout << sum2(1, 2, 3) << endl;
    cout << sum3(1, 2, 3) << endl;
    cout << sum4(1, 2, 3) << endl;
    cout << sum5(1, 2, 3) << endl;
    cout << sum6(1, 2, 3) << endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但为什么我们需要使用:

  1. non(val += args ...); 代替 val += args...;
  2. auto tmp = { val += args... }; 代替 val += args...;
  3. [](...){}((val += args)... ); 代替 val += args...;

它会更清晰,更容易使用:

template<typename T, typename ...Args>
inline T sum(T val, Args ...args) { val += args...; return val; }
Run Code Online (Sandbox Code Playgroud)

为什么标准中没有这种可能性,或者这种可能性是否会带来任何危险?

在C++ 17或更高版本中会出现这种可能吗?

Tar*_*ama 10

这是因为必须在需要语法列表的上下文中扩展参数包.正常的函数范围不是这样的上下文,所以你不能只写val += args...;.

但是,在C++ 17中,我们将获得折叠表达式,这将允许您重写代码,如下所示:

template<typename T, typename ...Args>
inline T sum(T val, Args ...args) { (val += ... += args) ; return val; }
Run Code Online (Sandbox Code Playgroud)

这将扩展(((val += arg0)) += arg1) += arg2)为三个参数.

另一种选择是这样写:

val += (... + args);
Run Code Online (Sandbox Code Playgroud)

这扩展到 val += ((arg0 + arg1) + arg2)


折叠表达式还支持扩展涉及参数包的任意表达式,如下所示:

(foo(args), ...);
((mymap[args] = 42), ...);
Run Code Online (Sandbox Code Playgroud)

这使您能够轻松地在功能范围内使用参数包扩展表达式.