可变参数函数模板指的是接受任意数量和类型的参数的函数模板,它具有语法上的可变参数,因此可以用于实现各种通用算法和容器。
定义可变参数函数模板需要使用模板参数包(template parameter pack)、函数参数包(function parameter pack)和参数包展开。
下面是可变参数函数模板的通用格式:
template <typename... Types>
RetType FuncName(Types... args);
其中,FuncName 是函数名,RetType 是函数返回值的类型。typename… Types 表示模板参数包,用于接受任意数量和类型的参数。Types… args 表示函数参数包,用于接受任意数量和类型的函数参数。
参数包展开是指将参数包中的每个参数都展开出来,以便进行相应操作。参数包展开可以使用递归、展开等技术来逐个处理每个参数,最终得到所需的结果。
函数模板的参数包通常需要使用递归函数 等实现。
更多展开方式
以下是可变参数函数模板的展开示例:
#include
// 递归终止条件
void print() {}
// 递归展开
template <typename T, typename... Types>
void print(T var1, Types... var2) {
std::cout << "var1 = " << var1 << std::endl;
print(var2...);
}
int main() {
print(1, 2.5, "hello");
return 0;
}
上述代码定义了一个可变参数函数模板 print,它递归展开参数包,并将每个参数打印输出。在递归展开的过程中,每次取出一个参数并打印,然后再递归调用函数本身,将剩余的参数包传入。
运行上述代码会输出以下结果:
var1 = 1
var1 = 2.5
var1 = hello
在函数模板中,可以使用 auto 关键字来推导参数包的类型,并且可以使用 decltype 关键字获取表达式的返回类型。
以下是可变参数函数模板的类型推导示例:
#include
template <typename... Types>
auto sum(Types... args) -> decltype((args + ...)) {
return (args + ...);
}
int main() {
std::cout << "sum(1, 2, 3, 4, 5) = " << sum(1, 2, 3, 4, 5) << std::endl;
std::cout << "sum(1.0, 2.5, 3.14) = " << sum(1.0, 2.5, 3.14) << std::endl;
return 0;
}
上述代码定义了一个可变参数函数模板 sum,它递归展开参数包,并将每个参数累加。在返回值中使用了 decltype 来推导累加操作的返回类型。
运行上述代码会输出以下结果:
sum(1, 2, 3, 4, 5) = 15
sum(1.0, 2.5, 3.14) = 6.64
可变参数类模板指的是接受任意数量和类型的参数的类模板,它能够用于实现各种通用容器和算法。
定义可变参数类模板需要使用模板参数包、继承等技术。
下面是可变参数类模板的通用格式:
template <typename... Types>
class ClassName {
public:
ClassName() {}
private:
// 成员变量和函数
};
其中,ClassName 是类名,typename… Types 表示模板参数包,用于接受任意数量和类型的参数。
参数包展开在类模板中可以作为类型参数、成员变量、成员函数等组成类的内容。类模板的参数包展开通常使用递归、继承等技术实现。
以下是可变参数类模板的展开示例:
#include
#include
// 递归终止条件
template <typename... Types>
class Tuple {};
// 类型展开
template <typename Head, typename... Tail>
class Tuple<Head, Tail...> : private Tuple<Tail...> {
public:
using Base = Tuple<Tail...>;
Tuple(Head head, Tail... tail) : m_head(head), Base(tail...) {}
private:
Head m_head;
};
int main() {
Tuple<int, double, std::string> t(1, 2.5, "hello");
return 0;
}
上述代码定义了一个可变参数类模板 Tuple,它采用递归展开参数包的方式,以实现支持任意数量和类型的元组。
在递归展开的过程中,每次取出一个参数并作为当前类的成员变量,然后再继承下一个元素所形成的类。由于继承是从左到右依次展开的,因此需要使用 private 继承来确保每个子类只包含自己的成员变量。
在类模板中,可以使用模板参数推导来推导参数包的类型。模板参数推导是 C++17 新增的功能,可以使用 auto 关键字和类模板构造函数,省略模板参数列表中的类型参数,让编译器自动推导出参数包的类型。
以下是可变参数类模板的类型推导示例:
#include
#include
template <typename... Types>
class Variant {
public:
template <typename T>
Variant(T value) : m_data(value) {}
private:
std::tuple<Types...> m_data;
};
int main() {
Variant v1(1);
Variant v2(3.14);
Variant v3("hello");
return 0;
}
上述代码定义了一个可变参数类模板 Variant,它支持任意数量和类型的值类型,并采用了 std::tuple 来管理这些值。由于模板参数可以在模板构造函数中推导出,因此不需要显式指定类型参数。
运行上述代码会输出以下结果:
1
3.14
hello