C++1zから、SFINAEによる「型に対して特性の操作ができるか」を判定するメタ関数の定義を容易にするために、void_t
というパラメータで任意の数の型を受け取ってなにもせずvoid
を返す型が定義されます。
namespace std {
template <class...>
using void_t = void;
}
私の著書『C++テンプレートテクニック 第2版』に掲載しているコードで、これまでのメタ関数定義と、void_t
を使用したメタ関数定義を比べてみます。
これまでの書き方で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は代入可能");
}
参照
お断り
この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。