C++之可变参数模板

简介

可变参数模板是模板编程时,模板参数(template parameter)的个数可变的情形,可变模板参数(variadic templates)是C++ 11新增的最强大的特性之一,它对参数进行高度泛化,它能表示0到任意个数、任意类型的参数。

C语言中以宏定义的方式实现可变参数

/*
用宏的方式
*/

#define add_1(a) a
#define add_2(a,b) a + b
#define add_3(a,b,c) a + add_2(b,c)

#define add(...)  PASTE(add_ ,GET_ARG_COUNT(__VA_ARGS__)) (__VA_ARGS__)

C++中的可变参数

…在参数的前面,代表的是定义参数
…在参数的后面,代表的是展开的语义

// ...在参数的前面,代表的是定义参数包
// ...在参数的后面,代表的是展开的语义
template<typename... Args>
void f(Args... args){
    constexpr auto s1 = sizeof...(Args); // 模板参数包
    constexpr auto s2 = sizeof...(args); // 函数参数包
    static_assert(s1 == s2);
}

参数包的遍历

递归遍历

// c++ 11 递归的方式
void print(){ }
template<typename A, typename... Args>
void print(const A& arg, const Args&... args){
    std::cout << arg << std::endl;
    print(args...);
}

C++17 折叠表达式遍历

右折叠: (参数包 二元操作符 … [二元操作符 初始值])
左折叠: ([初始值 二元操作符] … 二元操作符 参数包)

// 利用折叠表达式 + 逗号表达式 遍历
template<typename... Args>
void print(const Args&... args){
    ((std::cout << args << std::endl), ...); // 逗号表达式,使用右折叠
    // (... ,(std::cout << args << std::endl)); //使用的是左折叠
}

这里注意上下两种折叠方式的差别,上面使用的是右折叠表达式,下面采用的式左折叠表达式,在结果上两个的实现效果是完全一样的,但是在编译的时候是完全相反的,结果如下(可以看到展开的表达式中括号的差别):

#ifdef INSIGHTS_USE_TEMPLATE
template<>
void print<int, int, int, int, char[6], char>(const int & __args0, const int & __args1, const int & __args2, const int & __args3, const char (&__args4)[6], const char & __args5)
{
  (std::cout.operator<<(__args0).operator<<(std::endl)) , ((std::cout.operator<<(__args1).operator<<(std::endl)) , ((std::cout.operator<<(__args2).operator<<(std::endl)) , ((std::cout.operator<<(__args3).operator<<(std::endl)) , ((std::operator<<(std::cout, __args4).operator<<(std::endl)) , (std::operator<<(std::cout, __args5).operator<<(std::endl))))));
  (((((std::cout.operator<<(__args0).operator<<(std::endl)) , (std::cout.operator<<(__args1).operator<<(std::endl))) , (std::cout.operator<<(__args2).operator<<(std::endl))) , (std::cout.operator<<(__args3).operator<<(std::endl))) , (std::operator<<(std::cout, __args4).operator<<(std::endl))) , (std::operator<<(std::cout, __args5).operator<<(std::endl));

}
#endif

C++20折叠表达式 + apply + auto

可以用lambda就意味着可以用function和bind来实现更加灵活的调用

template<typename... Args>
void dump(const std::tuple<Args...>& tp){
    std::apply([](const auto&... args){
        ((std::cout << args << std::endl), ...);
    },tp);
}

参数包展开和折叠表达式对比

C++之可变参数模板_第1张图片
C++之可变参数模板_第2张图片

C++之可变参数模板_第3张图片

折叠表达式详解

你可能感兴趣的:(C++学习,c++,开发语言)