2016-09-11 6 views
6

考えると2種類TUを検出することtはタイプTのですt * uを記述することが可能であり、 uは、私がc++ detection idiomを使用しています)タイプUが、私はそれはすなわち(オブジェクトにそれらの間<code>operator *</code>を呼び出すことが可能ですかどうかを検出したい(static_assertsを考慮して)++演算子はCに存在し、呼び出し可能かどうか

ですが、それは私のコンパイラではまだ利用できませんので、私はこの

struct nonesuch { 
    nonesuch() = delete; 
    ~nonesuch() = delete; 
    nonesuch(nonesuch const&) = delete; 
    void operator=(nonesuch const&) = delete; 
}; 

namespace detail { 
template <class Default, class AlwaysVoid, template<class...> class Op, class... Args> 
struct detector { 
    using value_t = std::false_type; 
    using type = Default; 
}; 

template <class Default, template<class...> class Op, class... Args> 
struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> { 
    using value_t = std::true_type; 
    using type = Op<Args...>; 
}; 

} // namespace detail 

template <template<class...> class Op, class... Args> 
using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t; 

template< template<class...> class Op, class... Args > 
constexpr bool is_detected_v = is_detected<Op, Args...>::value; 

ないようにそれを自分自身を実装しました私は、このようなヘルパー持っW:

template <typename T, typename U> 
using multiply = decltype(std::declval<T>() * std::declval<U>()); 

をし、それは私が今

std::cout << is_detected_v<multiply, int, int> << std::endl; 
std::cout << is_detected_v<multiply, std::vector<int>, std::vector<int>> << std::endl; 

しかし、予想通りそれは、例えば、これは1を出力し、ほとんど大丈夫です0

bool can_multiply = is_detected_v<multiply, T, U> 

を呼び出す呼び出し可能なのかどうかを検出します私はクラスを持っています

ここA<bool>A<bool>で乗算することはできませんが、私のコードは、それは彼らがstatic_assertedたときに私の質問は、どのような方法を検出しないように自分のコードを修正している、

std::cout << is_detected_v<multiply, A<bool>, A<bool>> << std::endl; // 1 
A<bool>() * A<bool>(); // does't compile 

だから、可能だということを検出しますか?私はstatic_assertをいくつかのsfinaeに置き換えることができると思いますが、(私はアクセス権がなく、static_assertsにはより良いエラーメッセージがあるので)したくありません。

答えて

7

私の質問は、static_asserted時にメソッドを検出しないようにコードを修正する方法です。

あなたは単純にできません。それはstatic_assertの欠点の1つにすぎません。操作の正当性を外部的に検証する方法はありません。これは、operator*というインスタンス化の「直接のコンテキスト」でstatic_assertが発生しないためです。したがって、SFINAEは適用されません。常に困難なエラーになります。

私はstatic_assertをいくつかのsfinaeに置き換えることができますが、私は(私はアクセス権がなく、static_assertsにはより良いエラーメッセージがあるので)したくないと思います。

私は共感します。しかし、それは基本的にトレードオフです。 SFINAEとタイプチェック、またはstatic_assertと明確なエラー。 (もちろん、この場合は、テンプレート以外のテンプレートA<bool> operator*(A<bool> const&, A<bool> const&)を書くこともできますが、それはおそらくポイントの外にあります)。

+0

なぜ、役立つのか説明する(SFINAEのチェックは、オーバーロード解決中に行う必要があります。すべてのコンパイラーにすべての関数をコンパイルして、どのオーバーロードを呼び出すかを判断する前にすべての関数をコンパイルして判定します( 'T *'コードには深いネストされたコード2のレベルでエラーにつながるバグが含まれているので、私は 'T * 'より' void * 'を選んでいました)。 SFINAEの小切手は妥協であり、そこにさえMSVCはそれらに落ち着きます。 – Yakk

関連する問題