为什么我们在迭代可变模板参数时必须使用额外的构造?
Why do we have to use additional construction when iterating variadic template parameters?
为什么我们在迭代可变模板参数时必须使用额外的构造,例如(non()
- 函数,temp[]
- 数组,或空[](...){}
- lambda)?
众所周知,我们可以使用以下一些方法在 C++ 中使用可变参数模板迭代参数包:
#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;
}
但是为什么我们需要使用:
non(val += args ...);
而不是 val += args...;
auto tmp = { val += args... };
而不是 val += args...;
[](...){}((val += args)... );
而不是 val += args...;
这样会更清晰易用:
template<typename T, typename ...Args>
inline T sum(T val, Args ...args) { val += args...; return val; }
为什么标准中没有这种可能性,或者这种可能性会带来什么危险?
在 C++17 或更高版本中会有这种可能性吗?
这是因为必须在需要句法列表的上下文中扩展参数包。正常的函数范围不是这样的上下文,所以你不能只写 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), ...);
这使您能够轻松地在函数范围内使用参数包扩展表达式。
TarlanLlama 给出了答案。
在 C++17 中,使用 http://en.cppreference.com/w/cpp/language/fold 可以重写为:
template<typename ...Args>
decltype(auto) sum(Args ...args) {
return (... + args);
}
为什么我们在迭代可变模板参数时必须使用额外的构造,例如(non()
- 函数,temp[]
- 数组,或空[](...){}
- lambda)?
众所周知,我们可以使用以下一些方法在 C++ 中使用可变参数模板迭代参数包:
#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;
}
但是为什么我们需要使用:
non(val += args ...);
而不是val += args...;
auto tmp = { val += args... };
而不是val += args...;
[](...){}((val += args)... );
而不是val += args...;
这样会更清晰易用:
template<typename T, typename ...Args>
inline T sum(T val, Args ...args) { val += args...; return val; }
为什么标准中没有这种可能性,或者这种可能性会带来什么危险?
在 C++17 或更高版本中会有这种可能性吗?
这是因为必须在需要句法列表的上下文中扩展参数包。正常的函数范围不是这样的上下文,所以你不能只写 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), ...);
这使您能够轻松地在函数范围内使用参数包扩展表达式。
TarlanLlama 给出了答案。
在 C++17 中,使用 http://en.cppreference.com/w/cpp/language/fold 可以重写为:
template<typename ...Args>
decltype(auto) sum(Args ...args) {
return (... + args);
}