2017-08-22 17 views
6

static_assertのために関数が指定されたテンプレート引数に対して有効かどうかをテストするのに、detection idiom(または別の方法)を使用する方法はありますか?関数が失敗した場合の慣性検出static_assert

例を以下に意図したように(戻り型計算を失敗)fooの妥当性が検出されたことを示しているが、barのそれは(static_assertに失敗する)ではありません。

#include <iostream> 
#include <type_traits> 

template <typename... T> using void_t = void; 

template <class AlwaysVoid, template<class...> class Op, class... Args> 
struct detector: std::false_type { }; 

template <template<class...> class Op, class... Args> 
struct detector<void_t<Op<Args...>>, Op, Args...>: std::true_type { }; 

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

template <typename T> 
std::enable_if_t<!std::is_void<T>::value> foo() { 
    std::cout << "foo" << std::endl; 
} 

template <typename T> 
void bar() { 
    static_assert(!std::is_void<T>::value); 
    std::cout << "bar" << std::endl; 
} 

template <typename T> using foo_t = decltype(foo<T>()); 
template <typename T> using bar_t = decltype(bar<T>()); 

int main(int argc, char* argv[]) { 

    foo<int>(); 
    // foo<void>(); // fails as expected 

    bar<int>(); 
    // bar<void>(); // fails as expected 

    std::cout << std::boolalpha; 

    // detection works for foo 
    std::cout << is_detected<foo_t,int > << std::endl; // true 
    std::cout << is_detected<foo_t,void> << std::endl; // false 

    // but not for bar 
    std::cout << is_detected<bar_t,int > << std::endl; // true 
    std::cout << is_detected<bar_t,void> << std::endl; // true !!! 
} 

これはboost::lexical_castは、与えられた型に対して有効である場合、私は検出できない理由です。

答えて

6

SFINAE rules宣言で動作するため、SFINAEを使用して適切な出力を得ることはできません。

barのタイプは、常にvoid(void)となるため、SFINAEに関する限り、宣言は大丈夫です。

あなたが本当の検出イディオム(同様I did here)を書き上げ、そしてそのようにそれを使用する場合:あなたはSFINAEが成功し、定義が解析されたとき、あなたはコンパイラエラーを取得していることに気づくでしょう

template <typename T> 
using CanCallFoo_t = decltype(&foo<T>); 

template<class T> 
using CanCallFoo = detect<T, CanCallFoo_t, void>; 

template<class T> 
using CanCallBar_t = decltype(&bar<T>); 

template< class T> 
using 
CanCallBar = detect<T, CanCallBar_t, void>; 

//... 
std::cout << CanCallFoo<int>::value << std::endl; // true 
std::cout << CanCallFoo<void>::value << std::endl; // false 

std::cout << CanCallBar<int>::value << std::endl; 
std::cout << CanCallBar<void>::value << std::endl; 

error: static assertion failed
static_assert(!std::is_void<T>::value);

Demo

お知らせそれはvoid

static_assertのポイントは、他のより良い一致が見つからない場合はコンパイルが失敗することです

ためSFINAEを失敗するタイプを宣言しfoofooので年代に動作することを、 SFINAEの代用品としてではありません。

1

sfinaeでは、static_assertの検出や定義の置換に失敗した場合、Andyの答えは正しいと説明しています。私はあなたの問題を解決することが可能であることを指摘したがっていますが、いくつかの繰り返しの正しさを負う必要があります。

基本的に、汎用タイプにどのような種類の操作を適用しようとしているのかを調べる必要があります。次に、lexical_castを独自の関数で囲み、lexical_castに必要なすべてのプロパティに関数を渡します。これはエレガントではありませんが、関心のあるアプリケーションに関連するタイプにはいくつかの要件があることは疑いの余地があるので、実用的な解決策(おそらく)です。

多分これは明らかですが、私はまだそれがカバーされていないので、これを言及すると思った。

関連する問題