型Tを値保持するクラステンプレートにおいて(pair, tupleなど)、型Tコンストラクタの explicit 性を継承するイディオム。「ある型Uからの暗黙型変換を許可するか否か」という性質を、型Tをラップするクラステンプレートへと引き継ぐ。
2018-06-09追記:C++2a(C++20)標準に向けてP0892R1が採択され、条件付き explicit 指定子の追加によってstd::pair, std::tupleクラステンプレート定義が簡素化される。id:yohhoy:20180609参照。
2016-09-04追記:C++1z(C++17)標準ライブラリに向けてN4387が採択され、std::pair, std::tupleクラステンプレートに同テクニックが適用される。これにより、Uniform initializationによる tuple 初期化がサポートされる。
N4064 Improving pair and tuple, revision 2より説明コードを引用。コンストラクタA(U&&)にて、条件is_constructible<T,U>かつis_convertible<U,T>によるSFINAEを行う。
#include <type_traits> #include <utility> template<class T> struct A { // non-explicitコンストラクタ template<class U, typename std::enable_if< std::is_constructible<T, U>::value && std::is_convertible<U, T>::value , bool>::type = false > A(U&& u) : t(std::forward<U>(u)) {} // explicitコンストラクタ template<class U, typename std::enable_if< std::is_constructible<T, U>::value && !std::is_convertible<U, T>::value , bool>::type = false > explicit A(U&& u) : t(std::forward<U>(u)) {} T t; };
struct Im{ Im(int){} }; struct Ex{ explicit Ex(int){} }; A<Im> ai1(1); // OK A<Im> ai2{2}; // OK A<Im> ai3 = 3; // OK A<Im> ai4 = {4}; // OK A<Ex> ae1(1); // OK A<Ex> ae2{2}; // OK A<Ex> ae3 = 3; // Error A<Ex> ae4 = {4}; // Error
テンプレート引数Tに指定する型が explicit コンストラクタを持つ場合、A<Ex>クラスにも explicit コンストラクタを持たせる。そうでない場合は、A<Im>クラスでもコンストラクト時の暗黙型変換を許容する(上記例ではU=intからT=Imへの暗黙型変換)。
C++11(N3337) 20.9.4.3/p6, 20.9.6/p4より一部引用。
template <class T, class... Args> struct is_constructible;6 Given the following function prototype:
template <class T> typename add_rvalue_reference<T>::type create();the predicate condition for a template specialization
is_constructible<T, Args...>shall be satisfied if and only if the following variable definition would be well-formed for some invented variablet:T t(create<Args>()...);(snip)
template <class From, class To> struct is_convertible;4 Given the following function prototype:
template <class T> typename add_rvalue_reference<T>::type create();the predicate condition for a template specialization
is_convertible<From, To>shall be satisfied if and only if the return expression in the following code would be well-formed, including any implicit conversions to the return type of the function:To test() { return create<From>(); }(snip)
関連URL