type traits

本文阐述c++中的type_traits技术,即类型萃取。

示例代码

通过如下测试程序,练习type traits的使用。

1
2
3
4
5
template<typename T>
struct my_strait
{
using has_trivial_default_copy_constructor = __true_type;
};

设计两个类,分别具有nontrivial的copy-assignment和trivial的copy-assignment,很容易想到两个典型的类:String和Complex,我们写出他们的定义,其中String包含了自定义的nontrivial-copy-assignment:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
class String
{
friend ostream &operator<<(ostream &os, const String &rhs)
{
cout << rhs.ps;
return os;
}
private:
char *ps{};
size_t len{};
public:
String() = default;

explicit String(const char *s)
{
len = strlen(s);
ps = new char[len + 1];
strncpy(ps, s, len);
ps[len] = '\0';
}

String(const String &s) : ps(new char[s.len + 1]), len(s.len)
{
strncpy(ps, s.ps, len);
ps[len] = '\0';
}

String &operator=(const String &s)
{
if (this != &s)
{
delete[] ps;
len = s.len;
ps = new char[len + 1];
strncpy(ps, s.ps, len);
ps[len] = '\0';
}
return *this;
}

~String()
{
delete[] ps;
}
};

class Complex
{
friend ostream &operator<<(ostream &os, const Complex &rhs)
{
cout << rhs.real << " + " << rhs.imag << "i";
return os;
}

private:
double real{};
double imag{};
public:
Complex() = default;

Complex(double r, double i) : real(r), imag(i)
{}
};

为这两个类添加了重载<<输出运算符友元函数,方便我们输出对象的内容。

提供两个类相关的特化版本my_trait:

1
2
3
4
5
6
7
8
9
10
11
template<>
struct my_strait<String>
{
using has_trivial_default_copy_assign = __false_type;
};

template<>
struct my_strait<Complex>
{
using has_trivial_default_copy_assign = __true_type;
};

给出一个模板函数copy,其会根据传入的参数实际类型,是否具有trivial的默认拷贝赋值运算符,调用不同的重载函数copy_aux:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template <typename T>
void copy_aux(T &lhs, const T &rhs, __true_type)
{
cout << "this is true type copy\n";
lhs = rhs;
}

template <typename T>
void copy_aux(T &lhs, const T &rhs, __false_type)
{
cout << "this is false type copy\n";
lhs = rhs;
}

template <typename T>
void copy(T &lhs, const T &rhs)
{
using Temp = typename my_strait<T>::has_trivial_default_copy_assign;
copy_aux(lhs, rhs, Temp());
}

编写如下main函数测试,观察copy函数的执行情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int main()
{
cout <<"=============String================\n";
String s1("hello");
String s2;
copy(s2, s1);
cout << s1 << endl;
cout << s2 << endl;

cout <<"=============Complex================\n";
Complex c1(1.2, 3.4);
Complex c2;
copy(c2, c1);

cout << c1 << endl;
cout << c2 << endl;

cout <<"=============double================\n";
double a = 13.2;
double b = 2.1;
copy(b, a);
cout << a << endl;
cout << b << endl;

return 0;
}

执行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
=============String================
this is false type copy
hello
hello
=============Complex================
this is true type copy
1.2 + 3.4i
1.2 + 3.4i
=============double================
this is true type copy
13.2
13.2

我的电脑环境是Windows11系统,clion 2022,在Linux平台上应该也是一样的。