在 C++17 之前,
通过向模板类的构造函数传递参数无法推导出类的模板参数类型.
一般要通过一个帮助函数来构造一个对象,
通过传递给帮助函数的参数推导出参数类型,
然后在帮助函数中返回一个构造好的对象. 下面介绍 C++17 之前的做法与
C++17 的便利性.

演示用的模板类

template <typename T1, typename T2, typename T3>
class my_class {
    T1 t1;
    T2 t2;
    T3 t3;
public:
    explicit my_class(T1 t1_, T2 t2_, T3 t3_)
    : t1{t1_}, t2{t2_}, t3{t3_}

C++17 之前的做法

要构造 my_class 的对象, 可以通过下面的方法

my_class<int, int, float> obj{1, 2, 3.0};

通过上面这种方法, 当使用时要指定一堆的模板参数, 使用不太方便,
因此可以定义一个帮助函数, 比如 make_my_class

my_class<T1, T2, T3> make_my_class(T1 t1, T2 t2, T3 t3)
    return {t1, t2, t3};

之后就可以通过下面的方法构造对象 my_obj, 可以得到模板类类型为
my_class<int, int, double>.

auto my_obj (make_my_class(1, 2, 3.0));

C++17 的做法

在 C++17 中, 可以直接通过构造函数的参数类型来推导出模板参数类型.
因此可以象下面的方法构造对象 obj, 可以得到模板类类型为
my_class<int, int, double>.

my_class obj(1, 2, 3.0);

虽然 C++17 利用构造函数的参数类型来推导模板类型使用方便, 但有时候也无法推导,
考虑下面的类定义

// 模板类定义, 用于求和, 和存储于成员变量 value 中
<template <typename T>
struct sum {
    T value;
    template <typename ... Ts>
    sum(Ts&& ... values) : value{(values + ...)} {}
// 如果传递给构造函数的参数类型都相同, 可以推导出 T 的类型即为参数类型
sum my_sum{1, 2, 3};  // sum<int>::value 为 6
// 如果传递给构造函数的参数类型不同, 则会编译错误
// sum my_sum{1, 2, 3.0}

当然, 传递给 sum 构造函数的还可能会是 char*std::string.
为了使用其能正常工作, 需要寻找出众多参数类型中的最普通类型, 可以利用
std::common_type_t<...>. 在上面代码的基础上增加一个更加泛化的版本

// (1)
<template <typename T>
struct sum {
    T value;
    template <typename ... Ts>
    sum(Ts&& ... values) : value{(values + ...)} {}
// (2)
template <typename ... Ts>
sum(Ts&& ... ts) -> sum<std::common_type_t<Ts...>>;

此时, 如果传递给构造函数的参数类型相同, 直接会调用 (1) 的版本.
如果传递给构造函数的参数不同, 会调用 (2) 版本. 比如

// 得到 int, int, double 三种类型的普通类型为 double
// 最终会推导出一个 sum<double> 的结构类型
sum int_sum{1, 2, 3};
// 得到 std::string, const char* 更普通的类型为 std::string
// 最终会推导出一个 sum<std::string> 的结构类型
// sum <std::string>::value 为 std:string("abcdef")
sum string_sum {std::string{"abc"}, "def"};

从 C++17 开始, 可以很方便的构造一个模板类对象, 从而活动一个帮助函数. 在 C++
标准库中, 很多 make_XXX(...) 的帮助函数, 如 std::make_pair(),
std::make_tuple(), 在 C++17 之后, 这些帮助函数都会成为 deprecated 状态,
只是为前向兼容而保留.

演示用的模板类C++17 之前的做法C++17 的做法某些情况总结在 C++17 之前, 通过向模板类的构造函数传递参数无法推导出类的模板参数类型. 一般要通过一个帮助函数来构造一个对象, 通过传递给帮助函数的参数推导出参数类型, 然后在帮助函数中返回一个构造好的对象. 下面介绍 C++17 之前的做法与 C++17 的便利性.演示用的模板类temp...
C++中std::string是日常Coding中经常使用的一个类,使用起来非常方便,但是也存在一些弊端。 如下代码,参数传递的过程发生了内存分配(Memory Allocation)和内存拷贝。 void fun(const std::string& s) { std::cout << s << std::endl; const char* ch = "hello world"; // bad way, expensive if the string is long fun(ch); 再看下面的常用的字符串截取实现: // very long string std::strin
类型推导现代c++类型推演分为三个,一个为模板函数的形参推演。一个为auto的形参推演。一个decltype的类型推导。auto的类型推导是以模板函数类型推导为基础的。模板函数类型推导推导过程模板函数类型推导,是通过调用表达式即实参的类型模板函数相应的形参类型一 一匹配以此来推导模板参数类型。template<typename T> void f(ParamType param); std::complex<double> c{5.1,3.3};//不能省略double std::mutex mx; std::lock_guard<std::mutex> lg(mx);//std::muext也不能省略 c++ 17起,必须显式指定模板参数的约束得到了放宽。如果构造函数能...
一.泛型编程 在引入泛型编程之前,我们先来看这样一个问题,怎么做到实现一个通用的交换函数呢? 在C语言阶段我们可能会像下面这样写,需要分别实现不同类型的交换函数,又由于C语言不允许出现同名函数,所以函数名也需要不一样,写起来很繁琐 void Swapi(int* e1, int* e2) int tmp = *e1; *e1 = *e2; *e2 = tmp; void Swapd(double* e1, double* e2) double tmp =
因为c++ 17可以使用占位符类型(auto和decltype(auto))作为非类型模板参数类型。这意味着,我们可以为不同类型的非类型参数编写通用代码。 1. auto作为模板参数 从c++ 17起,可以使用auto来声明一个非类型模板参数。例如: template<auto N> class S { 这允许我们为不同类型实例化非类型模板参数N: S&lt...
C++中构造函数的几种类型包括: 1. 默认构造函数:不带任何参数构造函数,如果没有显式地定义,默认会自动生成。它的作用是创建一个对象并将其成员变量初始化为默认值。 2. 带参数构造函数:带有参数构造函数,可以根据传递的参数值来初始化对象的成员变量。 3. 拷贝构造函数:用于创建新对象并将已有对象的内容复制到新对象中的构造函数,其参数是一个同类型的对象。 4. 转换构造函数:只有一个参数构造函数,用于将该参数类型转换为类的对象类型,可以用来实现类型转换。 5. 移动构造函数:用于将一个对象的资源所有权转移到另一个对象,可以提高程序的性能。 这些构造函数的作用和参数类型都不同,可以根据需要进行选择和使用。