详解C++17中类模板参数推导的使用

 更新时间:2024年03月06日 09:53:41   作者:fengbingchun  
自C++17起就通过使用类模板参数推导,只要编译器能根据初始值推导出所有模板参数,那么就可以不指明参数,下面我们就来看看C++17中类模板参数推导的具体使用吧

在C++17之前,必须明确指出类模板的所有参数。自从C++17起必须指明类模板参数的限制被放宽了。通过使用类模板参数推导(Class Template Argument Deduction(CTAD)),只要编译器能根据初始值推导出所有模板参数,那么就可以不指明参数。

C++17中的类模板参数推导:允许从构造函数参数推导模板参数,简而言之,编译器可以根据构造函数参数自动推导它们,而不是显式指定模板参数。

用户定义的推导指南(User-defined deduction guides):允许你为类模板参数推导提供自定义规则。这些指南帮助编译器根据构造函数参数推断模板参数。

别名模板的推导(deduction for alias templates):允许你根据别名模板的基础类型或值(underlying type or value)推导别名模板的模板参数。

注意:

(1).推导过程中模板参数必须没有歧义。

(2).推导模板参数时不会使用隐式类型转换。

(3).仅当不存在模板参数列表时才执行类模板参数推导。如果指定了模板参数列表,则不会发生推导。

(4).类模板参数推导过程中会首先尝试以拷贝的方式初始化。

(5).类模板不能只指明一部分模板参数,然后指望编译器去推导剩余的部分参数。

(6).在任何情况下,对于像std::vector<>或其他STL容器一样拥有复杂的构造函数的类模板,强烈建议不要使用类模板参数推导,而是显式指明类型。

(7).智能指针没有推导指引。

以下为测试代码:

namespace {
 
template<typename T>
class Foo {
public:
	Foo(T value)
	{
		std::cout << "Created Foo, type id: " << typeid(T).name() << ", value: " << value << "\n";
	}
};
 
template<typename T>
class Foo2 {
public:
	Foo2(T value)
	{
		std::cout << "Created Foo2, type id: " << typeid(T).name() << ", value: " << value << "\n";
	}
};
 
// User-defined deduction guide 
template<typename T> Foo2(T)->Foo2<T>;
 
template<typename T> using MyAlias = T;
 
template<typename T>
class Foo3 {
public:
	Foo3(const std::initializer_list<T>& list) : vec_(list) {}
	void print() const
	{
		for (const auto& val : vec_) {
			std::cout << val << " ";
		}
		std::cout << "\n";
	}
 
private:
	std::vector<T> vec_;
};
 
} // namespace
 
int test_ctad()
{
	// 只要能根据初始值推导出所有模板参数就可以使用类模板参数推导
	// 推导过程支持所有方式的初始化(只要保证初始化是有效的)
	std::pair p(2, 4.5);     // deduces to std::pair<int, double> p(2, 4.5);
	std::tuple t(4, 3, 2.5); // same as auto t = std::make_tuple(4, 3, 2.5);
	std::complex c{ 5.1, 3.3 }; // std::complex<double>
	std::mutex mx;
	std::lock_guard lg{ mx }; // std::lock_guard<std::mutex>
	std::vector vec{ "hello", "world" }; // std::vector<const char*>
 
	std::vector v1{ 42 };
	std::vector v2{ v1 }; // v2也是一个std::vector<int>,这是花括号初始化总是把列表中的参数作为元素这一规则的一个例外
	// 然而,如果用多于一个元素的初值列来初始化的话,就会把传入的参数作为元素并推导出其类型作为模板参数
	std::vector vv{ v1, v2 }; // vv是一个vector<vector<int>>
 
 
	// 1.Class Template Argument Deduction(CTAD)
	// not specifying the type of the template
	auto foo11 = Foo(88); // Created Foo, type id: int, value: 88
	auto foo12 = Foo("Beijing"); // Created Foo, type id: char const * __ptr64, value: Beijing
 
	// specifying the type of the template
	Foo<int> foo21(88); // Created Foo, type id: int, value: 88
	Foo<const char*> foo22("Beijing"); // Created Foo, type id: char const * __ptr64, value: Beijing
 
 
	// 2.User-defined deduction guides
	// not specifying the type of the template
	auto foo31 = Foo2(88); // Created Foo2, type id: int, value: 88
	auto foo32 = Foo2("Beijing"); // Created Foo2, type id: char const * __ptr64, value: Beijing
 
 
	// 3.the deduction for alias templates
	MyAlias<int> alias1{ 88 };
	MyAlias<std::string> alias2{ "Beijing" };
 
	std::cout << "alias1: " << alias1 << "\n"; // alias1: 88
	std::cout << "alias2: " << alias2 << "\n"; // alias2: Beijing
 
	// reference: https://www.geeksforgeeks.org/class-template-argument-deduction-in-cpp-17/
	auto foo41 = Foo3({ 1, 2, 3, 4, 5 });
	foo41.print(); // 1 2 3 4 5
 
	return 0;
}

执行结果如下图所示:

GitHubhttps://github.com/fengbingchun/Messy_Test

到此这篇关于详解C++17中类模板参数推导的使用的文章就介绍到这了,更多相关C++17类模板参数推导内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++ Cartographer加载配置文件过程介绍

    C++ Cartographer加载配置文件过程介绍

    这篇文章主要介绍了Cartographer加载配置文件过程,谷歌优秀的激光SLAM开源框架Cartographer算法简单,但是程序部分太多需要学习的地方了,不论是整体框架的结构,还是数据的使用,都是非常优美的
    2023-03-03
  • C++的四种类型转换

    C++的四种类型转换

    这篇文章主要介绍了C++的四种类型转换,有详细的示例代码展示,对于学习C++的同学有一定的参考价值,感兴趣的同学可以参考本文
    2023-04-04
  • c++带有string的结构体赋值和清零问题

    c++带有string的结构体赋值和清零问题

    这篇文章主要介绍了c++带有string的结构体赋值和清零问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • C语言实现歌手大奖赛计分程序

    C语言实现歌手大奖赛计分程序

    这篇文章主要为大家详细介绍了C语言实现歌手大奖赛计分程序,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-03-03
  • C/C++中带空格字符串的输入讲解

    C/C++中带空格字符串的输入讲解

    这篇文章主要给大家介绍了关于如何解决C++中带空格字符串的输入问题,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来一起看看吧
    2021-09-09
  • 浅谈2路插入排序算法及其简单实现

    浅谈2路插入排序算法及其简单实现

    这篇文章主要介绍了浅谈2路插入排序算法及其简单实现,虽算不上是常用的排序方法,但在数据库等方面依然有用上的机会,需要的朋友可以参考下
    2015-08-08
  • C语言实现水波纹效果

    C语言实现水波纹效果

    这篇文章主要为大家详细介绍了C语言实现水波纹效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • 如何在C++中实现一个正确的时间循环器详解

    如何在C++中实现一个正确的时间循环器详解

    这篇文章主要给大家介绍了关于如何在C++中实现一个正确的时间循环器的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • C++微服务UserServer设计与实现方法详解

    C++微服务UserServer设计与实现方法详解

    在当今云原生时代,微服务架构已成为构建大规模分布式系统的主流选择,下面这篇文章主要介绍了C++微服务UserServer设计与实现的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-11-11
  • 浅析C/C++中动态链接库的创建和调用

    浅析C/C++中动态链接库的创建和调用

    下面小编就为大家带来一篇浅析C/C++中动态链接库的创建和调用。小编觉得挺不错的,现在分享给大家,也给大家做个参考,一起跟随小编过来看看吧
    2016-05-05

最新评论