c++17 推断指南(deduction guide)
namespace _nmsp2 { template<typename T> struct A { A(T val1, T val2) { cout << "A::A(T val1,T val2)执行了!" << endl; } A(T val) { cout << "A::A(T val)执行了!" << endl; } }; template<typename T> A(T)->A<T>; } namespace _nmsp3 { template<typename T> struct B { T m_b; T m_b2; }; template<typename T> B(T)->B<T>; template<typename T> B(T,T)->B<T>; }
c++17新概念:主要用来在推断类模板参数时提供推断指引。
(1)隐式的推断指南
针对类模板A的每个构造函数,都有一个隐式的模板参数推断机制存在,这个机制,被称为隐式的推断指南
template<typename T>
A(T,T)->A<T>;
表达出现->左侧部分内容或者形式时,请推断成->右侧的类型。右侧类型也被称为“指南类型”
->左侧部分:该推断指南所对应的构造函数的函数声明,多个参数之间用,分隔。
->右侧部分:类模板名,接着一个尖括号,尖括号中是模板参数名。
整个推断指南的含义:当用调用带两个参数的构造函数通过类模板A创建相关对象时,请用所提供的构造函数的实参来推断类模板A的模板参数类型,
一句话:推断指南的存在意义就是让编译器 能够把模板参数的类型推断出来。
template<typename T>
A(T,T)->A<double>;
那么:A aobj1(15, 16);代码行 相当于A<double> aobj1(15, 16);
(2)自定义的推断指南
_nmsp3::B bobj3{ 15 }; 不报错的原因
a)类B是聚合类。 是可以通过{}初始化的
b)B bobj3{ 15 }这种形式正好就相当于调用了类模板B的带一个参数(15)的构造函数,尽管类模板B中实际并不存在构造函数。
c)因为template<typename T>B(T)->B<T>;推断指南的存在,当调用了类模板B带一个参数的构造函数时,推断出来的类型为B<T>,所以
最终推断出来的类型为B<int>类型。
当我们定义一个模板类或者模板函数时,有时候编译器可能无法准确地推导模板参数,或者存在多个可能的推导结果,这时候就需要使用推断指南来明确告诉编译器我们期望的推导结果。
举例说明:
假设我们有一个模板类 Pair
,用于表示一对值。它有两个模板参数,分别表示这对值的类型。现在我们希望在传入两个参数时,编译器可以自动推导出这两个参数的类型,并实例化 Pair
类。但是,由于模板参数推导的规则,编译器可能无法准确地推导出这两个参数的类型,或者存在多个可能的推导结果。
这时候,我们可以使用推断指南来帮助编译器更准确地推导模板参数。例如:
cppCopy Code
template<typename T, typename U>
class Pair {
public:
T first;
U second;
Pair(T f, U s) : first(f), second(s) {}
};
如果我们使用如下方式创建一个 Pair
对象:
Pair p(5, 3.14);
编译器可能无法准确推导出 Pair
的模板参数类型,因为 5
可以是 int
、double
、float
等类型,而 3.14
可以是 double
或 float
类型。
为了明确告诉编译器我们期望的推导结果,我们可以提供一个推断指南,如下所示:
template<typename T, typename U>
Pair(T, U) -> Pair<T, U>;
这个推断指南告诉编译器,当我们传入两个参数时,应该推导出模板参数类型为 T
和 U
,从而实例化 Pair<T, U>
类。
通过使用推断指南,我们可以确保编译器能够正确推导模板参数,从而避免模板实例化过程中可能出现的错误或二义性。
template<typename T> class A { public: A(T const& t):s(t) {} T& show() { return s; } private: T s; }; // 推断指引 A(const char*)->A<std::string>; A(bool)->A<int>; A(int)->A<char>; int main() { A Int{40}; // input int cout << typeid(Int.show()).name() << endl; // output char A Bool{ true }; // input bool cout << typeid(Bool.show()).name() << endl; // output int A str{ "ssssss" }; // input char[] cout<<typeid(str.show()).name()<<endl; // output std::string return 0; }