折叠表达式
一元左折,一元右折
namespace detail1
{
// 一元左折
template <typename... T>
auto add_val(T... args)
{
return (... + args);
}
template <typename... T>
auto add_val2(T... args)
{
return (... - args);
}
// 一元右折
template <typename... T>
auto add_val3(T... args)
{
return (args + ...);
}
template <typename... T>
auto add_val4(T... args)
{
return (args - ...);
}
}
cout << "一元左折" << endl;
// 一元左折 (unary leftfold)
// 格式:(... 运算符 一包参数)
cout << detail1::add_val(10, 20, 30, 40); // (((10+20)+30)+40)
endl(cout);
cout << detail1::add_val2(10, 20, 30, 40); //(((10-20) -30)-40)
endl(cout);
cout << "一元右折" << endl;
// 一元右折 (unary leftfold)
// 格式:( 一包参数 运算符 ...)
cout << detail1::add_val3(10, 20, 30, 40); // (((40+30)+20)+10)
endl(cout);
cout << detail1::add_val4(10, 20, 30, 40); // (((40-30)-20)-10)
endl(cout);
二元左折,二元右折
namespace detail2
{
// 二元左折
template <typename... T>
auto add_val(T... args)
{
return (100 + ... + args);
}
template <typename... T>
auto add_val2(T... args)
{
return (100 - ... - args);
}
// 一元右折
template <typename... T>
auto add_val3(T... args)
{
return (args + ... + 100);
}
template <typename... T>
auto add_val4(T... args)
{
return (args - ... - 100);
}
template <typename... T>
void add_val5(T... args)
{
(cout << ... << args);
}
}
cout << "二元左折" << endl;
// 二元左折
// 格式:( init 运算符 ... 运算符 一包参数)
// init 表示一个初始的东西,它可能是一个值,也可能是个其他东西。
cout << detail2::add_val(10, 20, 30, 40); //((((100+10) +20)+30)+40)
endl(cout);
cout << detail2::add_val2(10, 20, 30, 40); // ((((100 - 10) - 20) - 30) - 40)
endl(cout);
cout << "二元右折" << endl;
// 二元右折 (unary leftfold)
// 格式:( 一包参数 运算符 ... 运算符 init)
// init 表示一个初始的东西,它可能是一个值,也可能是个其他东西。
// 当init 是一个值时
cout << detail2::add_val3(10, 20, 30, 40); // ((((40+30)+20)+10)+100)
endl(cout);
cout << detail2::add_val4(10, 20, 30, 40); //(10-(20- (30-(40-100))))
endl(cout);
// 当init 不是一个值,而是一个对象
detail2::add_val5(10, 20, 30, 40, " casdcsad ", "sdvsdvsdv"); // 10203040 casdcsad sdvsdvsdv *
// cout<<10<<20 cout 是对象 也就是init ,<< 是运算符 ,cout<<10 返回的是cout 对象
可变参表达式
namespace detail3
{
template <typename... Types>
void print(Types const &...args)
{
(std::cout << ... << args) << endl;
}
// todo 对参数包中所有的参数进行计算,将参数包中的所有的参数都翻倍,然后将结果传给 print()
template <typename... T>
void printDoubled(T const &...args)
{
print(args + args...);
}
// todo 对参数包中的每一个参数+1
template <typename... T>
void addOne(T const &...args)
{
// print(args + 1...); // ERROR: 1... is a literal with too many decimal points
// print(args + 1 ...); // OK
print((args + 1)...); // OK
}
}
// 调用
detail3::printDoubled(7.5, std::string("hello"), std::complex<float>(4, 2));
// 等效于调用
// print(7.5+7.5,
// std::string("hello") + std::string("hello"),
// std::complex<float>(4,2) + std::complex<float>(4,2));
detail3::addOne(11, 10, 12, 14, 15);
简化打印参数
同样也可以用该方法简化可变参数模板来打印参数:
template<typename... Types>
void print (Types const&... args)
{
(std::cout << ... << args) << '\n';
}
如果需要在元素间添加空格,需要额外的类模板:
// basics/addspace.hpp
template<typename T>
class AddSpace
{
private:
T const& ref; // refer to argument passed in constructor
public:
AddSpace(T const& r): ref(r) {
}
friend std::ostream& operator<< (std::ostream& os, AddSpace<T> s) {
return os << s.ref << ' '; // output passed argument add a space
}
};
template<typename... Args>
void print (Args... args){
(std::cout << ... << AddSpace(args) ) << '\n';
}
此例子中,AddSpace(args)
使用类模板实参推导,有AddSpace<Args>(args)
的作用,对于每一个实参创建一个AddSpace
的实例。