タイプをチェック

テンプレート メタプログラミングはコンパイル時のプログラミングです。しかし、テンプレート メタプログラミングと型特性ライブラリの共通点は何でしょうか?多くの!型特性ライブラリは、ライブラリで飼いならされた純粋なテンプレート メタプログラミングです。この投稿により、型特性ライブラリのプレゼンテーションがより構造化されます。

型のプロパティを確認

型特性ライブラリは、プライマリおよび複合型カテゴリをサポートしています。属性値で答えが得られます。

プライマリ タイプ カテゴリ

C++ には 14 の主要な型カテゴリがあります。それらは完全で直交しています。これは、各タイプが正確に 1 つのタイプ カテゴリのメンバーであることを意味します。型カテゴリのチェックは、型修飾子 const または volatile とは無関係です。

14 の主要なタイプ カテゴリ:

template <class T> struct is_void;
template <class T> struct is_integral;
template <class T> struct is_floating_point;
template <class T> struct is_array;
template <class T> struct is_pointer;
template <class T> struct is_reference;
template <class T> struct is_member_object_pointer;
template <class T> struct is_member_function_pointer;
template <class T> struct is_enum;
template <class T> struct is_union;
template <class T> struct is_class;
template <class T> struct is_function;
template <class T> struct is_lvalue_reference;
template <class T> struct is_rvalue_reference;

プライマリ タイプ カテゴリの適用は次のとおりです。

 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
// primaryTypeCategories.cpp

#include <iostream>
#include <type_traits>

struct A{
 int a;
 int f(int){return 2011;}
};

enum E{
 e= 1,
};

union U{
 int u;
};


int main(){
 
 std::cout << std::boolalpha << std::endl;

 std::cout << std::is_void<void>::value << std::endl;
 std::cout << std::is_integral<short>::value << std::endl;
 std::cout << std::is_floating_point<double>::value << std::endl;
 std::cout << std::is_array<int [] >::value << std::endl;
 std::cout << std::is_pointer<int*>::value << std::endl;
 std::cout << std::is_reference<int&>::value << std::endl;
 std::cout << std::is_member_object_pointer<int A::*>::value << std::endl;
 std::cout << std::is_member_function_pointer<int (A::*)(int)>::value << std::endl;
 std::cout << std::is_enum<E>::value << std::endl;
 std::cout << std::is_union<U>::value << std::endl;
 std::cout << std::is_class<std::string>::value << std::endl;
 std::cout << std::is_function<int * (double)>::value << std::endl; 
 std::cout << std::is_lvalue_reference<int&>::value << std::endl;
 std::cout << std::is_rvalue_reference<int&&>::value << std::endl;
 
 std::cout << std::endl;

} 


22 行目のフラグ std::boolalpha の使用のおかげで、プログラムは 1 または 0 の代わりに true または false を表示します。14 のプライマリ タイプ カテゴリの各呼び出しは true を返します。

魔法の仕組み

この手法の鍵は、テンプレートとテンプレートの特殊化、いくつかの規則、および多くの入力に基づいています。関数テンプレート std::integral の可能な実装を書きました。 std::integral は、型が整数かどうかをチェックします。

 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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// integral.cpp

#include <iostream>
#include <type_traits>

namespace rgr{

 template<class T, T v>
 struct integral_constant {
 static constexpr T value = v;
 typedef T value_type;
 typedef integral_constant type;
 constexpr operator value_type() const noexcept { return value; }
 constexpr value_type operator()() const noexcept { return value; } //since c++14
 };

 typedef integral_constant<bool, true> true_type;
 typedef integral_constant<bool, false> false_type;

 template <class T>
 struct is_integral : public false_type{};

 template <>
 struct is_integral<bool> : public true_type{};

 template <>
 struct is_integral<char> : public true_type{};

 template <>
 struct is_integral<signed char> : public true_type{};

 template <>
 struct is_integral<unsigned char> : public true_type{};

 template <>
 struct is_integral<wchar_t> : public true_type{};

 template <>
 struct is_integral<short> : public true_type{};

 template <>
 struct is_integral<int> : public true_type{};

 template <>
 struct is_integral<long> : public true_type{};

 template <>
 struct is_integral<long long> : public true_type{};

 template <>
 struct is_integral<unsigned short> : public true_type{};

 template <>
 struct is_integral<unsigned int> : public true_type{};

 template <>
 struct is_integral<unsigned long> : public true_type{};

 template <>
 struct is_integral<unsigned long long> : public true_type{};
 
}

int main(){
 
 std::cout << std::boolalpha << std::endl;
 
 std::cout << "std::is_integral<int>::value: " << std::is_integral<int>::value << std::endl;
 std::cout << "rgr::is_integral<int>::value: " << rgr::is_integral<int>::value << std::endl;
 
 std::cout << "std::is_integral<double>::value: " << std::is_integral<double>::value << std::endl;
 std::cout << "rgr::is_integral<double>::value: " << rgr::is_integral<double>::value << std::endl;
 
 std::cout << std::endl;
 
 std::cout << "std::true_type::value: " << std::true_type::value << std::endl;
 std::cout << "rgr::true_type::value: " << rgr::true_type::value << std::endl;
 
 std::cout << "std::false_type::value: " << std::false_type::value << std::endl;
 std::cout << "rgr::false_type::value: " << rgr::false_type::value << std::endl;
 
 std::cout << std::endl;
 
 std::cout << "std::integral_constant<bool, true>::value: " << std::integral_constant<bool, true>::value << std::endl;
 std::cout << "rgr::integral_constant<bool, true>::value: " << rgr::integral_constant<bool, true>::value << std::endl;
 
 std::cout << "std::integral_constant<bool, false>::value: " << std::integral_constant<bool, false>::value << std::endl;
 std::cout << "rgr::integral_constant<bool, false>::value: " << rgr::integral_constant<bool, false>::value << std::endl; 
 
 std::cout << std::endl;
 
}

実装で名前空間 rgr を使用し、実装を名前空間 std の型特性の実装と比較します。関数テンプレート rgr::is_integral::value (69 行目) の呼び出しにより、式 rgr::true_type::value (77 行目) が呼び出されます。これは、integral が true_type から派生しているためです。 (42行目)。 rgr::true_type::value は、rgr::integral_constant::value (17 行目) のエイリアスです。この例では、クラス integral_constant の static constexpr 値のみを使用しています。 integral_constant は、型特性関数の基本クラスです。

完全を期すために、プログラムの出力。私の実装は、型特性ライブラリのように動作します。

14 の主要な型カテゴリに基づいて、C++ には 7 つの複合型カテゴリがあります。

複合型カテゴリ


is_fundamental タイプ カテゴリは関数テンプレート is_same を使用します。 I については、次回の投稿で型特性ライブラリとの型比較について詳しく説明します。

type-traits を使用すると、より多くの型チェックが可能になります。

タイプ プロパティ

プライマリおよび複合タイプのカテゴリに加えて、タイプ プロパティを確認できます。

 template <class T> struct is_const;
 template <class T> struct is_volatile;
 template <class T> struct is_trivial;
 template <class T> struct is_trivially_copyable;
 template <class T> struct is_standard_layout;
 template <class T> struct is_pod;
 template <class T> struct is_literal_type;
 template <class T> struct is_empty;
 template <class T> struct is_polymorphic;
 template <class T> struct is_abstract;
 template <class T> struct is_signed;
 template <class T> struct is_unsigned;
 template <class T, class... Args> struct is_constructible;
 template <class T> struct is_default_constructible;
 template <class T> struct is_copy_constructible;
 template <class T> struct is_move_constructible;
 template <class T, class U> struct is_assignable;
 template <class T> struct is_copy_assignable;
 template <class T> struct is_move_assignable;
 template <class T> struct is_destructible;
 template <class T, class... Args> struct is_trivially_constructible;
 template <class T> struct is_trivially_default_constructible;
 template <class T> struct is_trivially_copy_constructible;
 template <class T> struct is_trivially_move_constructible;
 template <class T, class U> struct is_trivially_assignable;
 template <class T> struct is_trivially_copy_assignable;
 template <class T> struct is_trivially_move_assignable;
 template <class T> struct is_trivially_destructible;
 template <class T, class... Args> struct is_nothrow_constructible;
 template <class T> struct is_nothrow_default_constructible;
 template <class T> struct is_nothrow_copy_constructible;
 template <class T> struct is_nothrow_move_constructible;
 template <class T, class U> struct is_nothrow_assignable;
 template <class T> struct is_nothrow_copy_assignable;
 template <class T> struct is_nothrow_move_assignable;
 template <class T> struct is_nothrow_destructible;
 template <class T> struct has_virtual_destructor;

is_trivially_copyable のような関数テンプレートの多くには、自明な名前コンポーネントがあります。つまり、これらのメソッドは、開発者ではなくコンパイラによって生成される必要があります。キーワード default を使用してコンパイラから明示的に要求するメソッドも自明です。

次は?

型特性ライブラリには多くの機能があります。コンパイル時の型比較と型変更については次の記事で書きます。