selph
selph
Published on 2022-04-10 / 696 Visits
0
0

C++折叠表达式

觉得自己还是需要好好去学一门编程语言,嗯,就C++吧

折叠表达式简介

C++11提供了可变模板参数包,使函数可以接受任意数量的参数。但在C++11中展开参数包稍显麻烦,而 C++17 的折叠表达式使得展开参数包变得容易, 其基本语法是使用 (…) 的语法形式进行展开。

折叠表达式支持的操作符:

+, -, *, /, %, ^, &, |, =, <,
>, <<, >>, +=, -=, *=, /=, %=, ^=, &=, |=, <<=,
>>=,==, !=, <=, >=, &&, ||, ,, .*, ->*.

一元折叠示例

折叠分类:左折叠和右折叠

// 右折叠
template<typename ... T>
auto sum_right(T ... t) {
    return (t + ...);
}

// 左折叠
template<typename ... T>
auto sum_left(T ...t) {
    return (... + t);
}

int main()
{
    std::cout << sum_left(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) << std::endl;
    return 0;
}

左折叠反汇编:

00007FF6F44749BC 8B 85 E8 00 00 00    mov         eax,dword ptr [<t_1>] 
00007FF6F44749C2 8B 8D E0 00 00 00    mov         ecx,dword ptr [<t_0>] 
00007FF6F44749C8 03 C8                add         ecx,eax  
00007FF6F44749CA 8B C1                mov         eax,ecx  
00007FF6F44749CC 03 85 F0 00 00 00    add         eax,dword ptr [<t_2>] 
00007FF6F44749D2 03 85 F8 00 00 00    add         eax,dword ptr [<t_3>] 
00007FF6F44749D8 03 85 00 01 00 00    add         eax,dword ptr [<t_4>] 
00007FF6F44749DE 03 85 08 01 00 00    add         eax,dword ptr [<t_5>] 
00007FF6F44749E4 03 85 10 01 00 00    add         eax,dword ptr [<t_6>] 
00007FF6F44749EA 03 85 18 01 00 00    add         eax,dword ptr [<t_7>] 
00007FF6F44749F0 03 85 20 01 00 00    add         eax,dword ptr [<t_8>] 
00007FF6F44749F6 03 85 28 01 00 00    add         eax,dword ptr [<t_9>] 

显然左折叠类似于这种结合的方式进行执行

(((1 + 2) + 3) + 4) + 5

右折叠则相反

二元折叠示例

前例中如果参数是空的,则会报错,可以通过加上一个数值0(缺省值)来解决编译错误,这就变成了二元折叠

示例:

template<typename ... T>
auto sum_right(T ... t) {
    return (t + ... + 0);
}
template<typename ... T>
auto sum_left(T ...t) {
    return (0 + ... + t);
}

这样一来,即便函数给的参数是空的,也能正常执行编译不报错了

空参数包就是参数包中不含任何参数。

对于大多数操作符,空参数包将会引发编译错误。

对于 && 或 ||,空参数包是合法的,其中 && 的展开结果为 true,||
的展开结果为 false。在逗号 , 操作符中,空参数包也合法,展开为 void()。

示例

计算指定集合内包含指定数值的个数

template<typename R ,typename ...T>
auto count(const R& range, T...t) {
    return (std::count(std::begin(range), std::end(range), t) + ... + 0);
}

int main()
{
    std::vector<int> scores = { 1,2,3,4,5,6,7,8,9,10};
    std::cout << count(scores,3,5,7) << std::endl;          // 3
    std::cout << count("hello world",'o','l') << std::endl; // 5
    return 0;
}

这是右折叠的方式进行函数调用,就是对参数中最右边两个数进行指定运算,结果与从右边起的下一个数继续进行运算,而进行的运算就是这里()里指定的对...的模板参数进行的运算,这里就是std::count(std::begin(range), std::end(range), t) + ...,就是对每一个t都进行这个运算然后都相加

连续打印不同类型的值

template<typename...T>
auto sel_dbgprint(T...t) {
    (std::cout << ... << t) << std::endl;// 折叠表达式需要放在小括号里使用
}

int main()
{
    sel_dbgprint("ERROR::",250,"::妙啊");
    return 0;
}

参考资料:


Comment