C++1zから、SFINAEによる「型に対して特性の操作ができるか」を判定するメタ関数の定義を容易にするために、void_t
というパラメータで任意の数の型を受け取ってなにもせずvoid
を返す型が定義されます。
// <type_traits> namespace std { template <class...> using void_t = void; }
私の著書『C++テンプレートテクニック 第2版』に掲載しているコードで、これまでのメタ関数定義と、void_t
を使用したメタ関数定義を比べてみます。
型Tがiterator型を持っているか判定する
これまでの書き方でhas_iterator
メタ関数を定義する:
#include <type_traits> struct has_iterator_impl { template <class T> static std::true_type check(typename T::iterator*); template <class T> static std::false_type check(...); }; template <class T> struct has_iterator : decltype(has_iterator_impl::check<T>(nullptr)) {}; #include <vector> int main() { static_assert( has_iterator<std::vector<int>>::value, "vectorはiterator型を持っている"); static_assert( !has_iterator<int>::value, "intはiterator型を持っていない"); }
void_t
を使用した場合:
#include <type_traits> template <class, class = void> struct has_iterator : std::false_type {}; template <class T> struct has_iterator<T, std::void_t<typename T::iterator>> : std::true_type {}; #include <vector> int main() { static_assert( has_iterator<std::vector<int>>::value, "vectorはiterator型を持っている"); static_assert( !has_iterator<int>::value, "intはiterator型を持っていない"); }
だいぶ短くなりました。
型Tが代入可能か判定する
これまでの書き方でis_assignable
を定義する:
#include <type_traits> #include <utility> struct is_assignable_impl { template <class T> static auto check(T*) -> decltype( std::declval<T&>() = std::declval<const T&>(), std::true_type()); template <class T> static auto check(...) -> std::false_type; }; template <class T> struct is_assignable : decltype(is_assignable_impl::check<T>(nullptr)) {}; struct A { A& operator=(const A&) = delete; }; struct B {}; int main() { static_assert(!is_assignable<A>::value, "Aは代入不可"); static_assert( is_assignable<B>::value, "Bは代入可能"); }
void_t
を使用した場合:
#include <type_traits> #include <utility> template <class, class = void> struct is_assignable : std::false_type {}; template <class T> struct is_assignable< T, std::void_t<decltype(std::declval<T&>() = std::declval<const T&>())> > : std::true_type {}; struct A { A& operator=(const A&) = delete; }; struct B {}; int main() { static_assert(!is_assignable<A>::value, "Aは代入不可"); static_assert( is_assignable<B>::value, "Bは代入可能"); }
参照
- N3911 TransformationTrait Alias
void_t
- N4502 Proposing Standard Library Support for the C++ Detection Idiom, v2
void_t
を使用したイディオムをサポートするためのツールキットの提案。これは採択されていないが、ツールとしては有用なので適時使用するとよいだろう
- Detection Idiom - yohhoyの日記
お断り
この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。