型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