要件を強制するために使用しないでください。enable_if
を使用enable_if
すると、関数が「消える」ため、ユーザーは非常に混乱する可能性があります。典型的な症状は、のようなエラーメッセージです。これでは、要件が違反していることをユーザーに正確に伝えることはできません。error: no matching function for call to expression
static_assert
C++0x を想定して、代わりに を使用して要件を適用する必要があります。C++03 を使用している場合、static_assert
(Boost などのSTATIC_ASSERT
) エミュレーションを使用する必要があるかどうかは、通常、1 つのエラー メッセージを別のエラー メッセージと交換することを意味するため、トスアップです。
対比:
// SFINAE for types that do not decay to int
template<
typename T
, typename = typename std::enable_if<
std::is_same<
typename std::decay<T>::type
, int
>::value
>::type
>
void
f(T&&)
{}
// using static assert instead
template<
typename T
>
void
g(T&&)
{
static_assert( std::is_same<typename std::decay<T>::type, int>::value
, "Constraints violation" );
}
GCC を使用すると、次のエラーが表示されf("violation")
ます (両方のメッセージにファイル名と行番号が付いています)。
error: no matching function for call to 'f(const char [10])'
一方、g("violation")
利回り:
error: static assertion failed: "Constraints violation"
foo: parameter type must be CopyConstructible
ここで、テンプレート内などのアサーションで明確で明示的なメッセージを使用することを想像してくださいfoo
。
そうは言っても、 SFINAE とstatic_assert
は多少敵対的であるため、明示的な制約違反メッセージと巧妙なオーバーロードの両方を持つことは、常に可能または簡単であるとは限りません。
やりたいことは、Boost.ConceptCheckを使用して簡単に実現できます。ただし、アウトオブライン コードである Constraint クラスを記述する必要があります。また、利用可能な場所で使用するとは思わないstatic_assert
ため、エラーメッセージはそれほど良くないかもしれません. これは将来変更される可能性があります。
もう 1 つの可能性は、static_assert
+ 型の特性を使用することです。このアプローチの興味深い点は、C++0x のライブラリには一連の有用な特性が付属していることです。これらの特性は、行外のコードを記述せずにすぐに使用できます。さらに興味深いのは、トレイトの使用は制約の記述に限定されず、巧妙なオーバーロードを作成するために SFINAE と共に使用することもできることです。
ただし、おそらく C++ が関数の名前を処理する方法が原因で、型が操作の特定のメンバーをサポートしているかどうかをチェックするためにすぐに利用できる特性はありません。has_member<T, &T::member_to_test_for>
テスト対象のメンバーがそもそも存在する場合にのみ意味があるため、どちらのようなものも使用できません(オーバーロードのようなものや、メンバーの署名をトレイトに渡す必要があるという事実は無視してください)。
任意の式をトレイトに変換する方法は次のとおりです。
template<typename T>
struct void_ {
typedef void type;
};
template<typename T>
struct trait {
private:
typedef char yes[1];
typedef char no[2];
template<typename U>
static
yes&
test(U&&
, typename void_<decltype( std::declval<U&>().member() )>::type* = 0);
static
no&
test(...);
public:
static constexpr bool value = sizeof test(std::declval<T>()) == sizeof(yes);
};
これがいかに大きいかに注意してください。Boost.ConceptCheck 制約クラスを作成する方が簡単かもしれません (ただし、SFINAE では再利用できないことに注意してください)。
任意の式はstd::declval<U&>().member()
です。ここでの要件は、左辺値参照が与えられた場合U
(または、必要に応じT
て特性が true の場合)、それに対する呼び出しmember()
が有効であることです。
また、その式の型 (つまり、この式に対して選択されたオーバーロードの結果の型) が型に変換可能であることを確認することもできます (それがmember
その型であるかどうかを確認しないでください。正当な理由もなく制限が厳しすぎるためです)。ただし、これはトレイトを膨らませますが、これも制約クラスを優先します。
関数テンプレートの署名の一部を作成する方法はわかりませんがstatic_assert
(これはあなたが望むもののようです)、クラス テンプレート内に表示できます。Boost.ConceptCheck もそれをサポートしていません。