型特性ライブラリ:型チェック

型特性ライブラリは C++11 の一部であり、コンパイル時の型チェック、型比較、および型変更をサポートします。このライブラリには 100 を超える関数がありますが、新しい C++ 標準がリリースされるたびに増えています。今日は型チェックについて紹介します。

型チェック

各タイプは、14 の主要なタイプ カテゴリの 1 つに正確に属します。

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

ここにそれらすべてがあります:

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_null_pointer;
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;

次のプログラムは、これらの主要な型カテゴリのそれぞれについてチェックを満たす型の例を示しています。

// 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() { using namespace std; cout << boolalpha << '\n'; cout << is_void<void>::value << '\n'; // true cout << is_integral<short>::value << '\n'; // true cout << is_floating_point<double>::value << '\n'; // true cout << is_array<int []>::value << '\n'; // true cout << is_pointer<int*>::value << '\n'; // true cout << is_null_pointer<nullptr_t>::value << '\n'; // true cout << is_member_object_pointer<int A::*>::value << '\n'; // true cout << is_member_function_pointer<int (A::*)(int)>::value << '\n'; // true cout << is_enum<E>::value << '\n'; // true cout << is_union<U>::value << '\n'; // true cout << is_class<string>::value << '\n'; // true cout << is_function<int * (double)>::value << '\n'; // true cout << is_lvalue_reference<int&>::value << '\n'; // true cout << is_rvalue_reference<int&&>::value << '\n'; // true }

この魔法の仕組み

この手法は、テンプレートとテンプレートの特殊化、いくつかの規則、および多くの入力に基づいています。関数テンプレート std::integral. std::integralの簡略版を書きました 指定された型が整数型かどうかを確認します。 const を無視します または volatile

// 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; // (2)
 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{}; // (3)

 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 << '\n';
 
 std::cout << "std::is_integral<int>::value: " << std::is_integral<int>::value << '\n';
 std::cout << "rgr::is_integral<int>::value: " << rgr::is_integral<int>::value << '\n'; // (1)
 
 std::cout << "std::is_integral<double>::value: " << std::is_integral<double>::value << '\n';
 std::cout << "rgr::is_integral<double>::value: " << rgr::is_integral<double>::value << '\n';
 
 std::cout << '\n';
 
 std::cout << "std::true_type::value: " << std::true_type::value << '\n';
 std::cout << "rgr::true_type::value: " << rgr::true_type::value << '\n';
 
 std::cout << "std::false_type::value: " << std::false_type::value << '\n';
 std::cout << "rgr::false_type::value: " << rgr::false_type::value << '\n';
 
 std::cout << '\n';
 
 std::cout << "std::integral_constant<bool, true>::value: " << std::integral_constant<bool, true>::value << '\n';
 std::cout << "rgr::integral_constant<bool, true>::value: " << rgr::integral_constant<bool, true>::value << '\n';
 
 std::cout << "std::integral_constant<bool, false>::value: " << std::integral_constant<bool, false>::value << '\n';
 std::cout << "rgr::integral_constant<bool, false>::value: " << rgr::integral_constant<bool, false>::value << '\n'; 
 
 std::cout << '\n';
 
}

私は自分の実装で名前空間 rgr を使用しています 名前空間 std の型特性関数と比較します .関数テンプレートの呼び出し rgr::is_integral<int>::value (1) 式 rgr::true_type::value の呼び出しを引き起こします (2)、なぜなら integral<int> true_type から派生 (3)。 rgr::true_type::value rgr::integral_constant<bool, true>::value のエイリアスです (2)。この例では、静的な constexpr を使用しています クラス integral_constant の値 . integral_constant 型特性関数の基本クラスです。

完全を期すために、ここにプログラムの出力を示します。型特性ライブラリの関数など、私の実装でも同じ結果が得られます。

関数テンプレート rgr::is_integraで使用します l ::value リターンとして。前回の記事「テンプレート メタプログラミング - 仕組み」のこの規則を覚えているでしょうか?右!私の関数テンプレート rgr::is_integral はメタ関数であり、テンプレート メタプログラミングの命名規則を使用します。 C++17 以降、規則のために ::value のヘルパー クラスがあります。 .このヘルパー クラスは変数テンプレートに基づいています。

template< class T >
inline constexpr bool is_integral_v = is_integral<T>::value

変数テンプレートは基本的に変数のファミリーです。このヘルパー クラスにより、 std::integral_v<T> と記述できます。 std::integral<T>::value の代わりに .この短縮表記は、型特性ライブラリのすべての関数テンプレートで機能します。

次に、これらの主要なタイプ カテゴリから複合タイプ カテゴリが組み立てられます。

複合タイプ カテゴリ

7 つの複合型カテゴリがあります。次の表にそれらを示します。

さらに、プライマリ型カテゴリと複合型カテゴリに加えて、型特性ライブラリは型プロパティと型プロパティ クエリを提供します。完全を期すために、ここにそれらを示します。

タイプ プロパティ

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_empty;
template <class T> struct is_polymorphic;
template <class T> struct is_abstract;
template <class T> struct is_final;
template <class T> struct is_aggregate;
 
template <class T> struct is_signed;
template <class T> struct is_unsigned;
template <class T> struct is_bounded_array;
template <class T> struct is_unbounded_array;
template <class T> struct is_scoped_enum;
 
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, class U> struct is_swappable_with;
template <class T> struct is_swappable;
 
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, class U> struct is_nothrow_swappable_with;
template <class T> struct is_nothrow_swappable;
 
template <class T> struct is_nothrow_destructible;
 
template <class T> struct has_virtual_destructor;
 
template <class T> struct has_unique_object_representations;

std::is_trivially_copyable のようなメタ関数の多く 彼らの名前には些細なことがあります。これは、コンパイラがこのメソッドを提供することを意味します。キーワード default を使用してコンパイラにメソッドを要求する

タイプ プロパティ クエリ

template <class T> struct alignment_of;
template <class T> struct rank;
template <class T, unsigned I = 0> struct extent;

次は?

関数 std::is_sameに気づきましたか 複合型カテゴリ std::is_fundamenta 私? std::is_same コンパイル時に型比較を提供するため、特別です?コンパイル時の型比較については次の投稿で書きます。