2016-08-02 31 views
3

为什么我们要使用额外的建筑,如迭代可变参数模板参数时(non() - 拉姆达功能,temp[] - - 阵列,或空[](...){})?为什么迭代可变参数模板时我们必须使用额外的构造?

众所周知,我们可以利用其中的一些方法迭代与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; 
} 

,但为什么我们需要使用:

  1. non(val += args ...);代替val += args...;
  2. auto tmp = { val += args... };,而不是0123的
  3. [](...){}((val += args)...);代替val += args...;

这将是更清晰,更易于使用,因此:

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

为什么没有出现在标准这样的可能性,或者可以这样一种可能性携带任何危险?

而且会出现这样的可能性在C++ 17或更高?

+0

另外,用'如果constexpr',你不需要额外的重载来处理可变参数模板参数包。 –

+0

@Johannes Schaub - litb谢谢。你的意思是这样的吗? http://melpon.org/wandbox/permlink/bNWHskOvPU7pieH5但在C++ 1z的GCC 7.0中,这仍然不被支持。它可能出现在哪个C++ 17/...标准中? – Alex

回答

10

这是因为参数包必须在预计句法列表上下文进行扩展。正常的函数作用域不是这样的上下文,所以你不能只写val += args...;

然而,在C++ 17中,我们会得到fold expressions,这将让你重写,像这样的代码:

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

这将扩大到(((val += arg0)) += arg1) += arg2)的三个参数。

另一种办法是把它写这样的:

val += (... + args); 

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


折表达式也将支持扩大涉及参数包任意表达式,像这样:

(foo(args), ...); 
((mymap[args] = 42), ...); 

这使您能够扩大EXPR电源带参数包的会话在功能范围内很容易。

+0

谢谢!是的,自GCC 6.1开始,我可以用'-std = C++ 1z'来做到这一点:https://godbolt.org/g/CAo0Mp – Alex

+0

你真的需要提到基于fold的表达式。 – Yakk

+0

@Yakk更好吗? – TartanLlama

相关问题