2017-07-09 14 views
1

Iは、以下のアプローチを使用して第1 void_tことなく、is_union_or_classを実装しようとした:C++ 2つのis_union_or_class実装

#include <type_traits> 

    namespace detail { 
     template <class T> 
     struct is_union_or_class_helper1 : public std::false_type { }; 
     template <class T> 
     struct is_union_or_class_helper1<char T::*> : public std::true_type { }; 
    } 

template <class T> 
struct is_union_or_class1 : public detail::is_union_or_class_helper1<T> { }; 

そしてIはfalseに評価ダミー空のクラスとvalue部材を使用して試験しました。そして、私はこのようなvoid_tを使用して再試行:

#include <type_traits> 

template <class...> 
using void_t = void; 

    namespace detail { 
     template <class T, class = void_t<T>> 
     struct is_union_or_class_helper2 : public std::false_type { }; 
     template <class T> 
     struct is_union_or_class_helper2<T, void_t<char T::*>> : public std::true_type { }; 
    } 

template <class T> 
struct is_union_or_class2 : public detail::is_union_or_class_helper2<T> { }; 

そして、それはtrueに正しく評価され、この時間。なぜ結果は異なるのですか?両方のヘルパーは、char T::*が有効な式である場合にはより専門的です。なぜなら、2番目のケースのヘルパーだけがtrue_typeから継承するのはなぜですか? MSVC 2015コンパイラでこのコードとテストをコンパイル

struct dummy_type { }; 

int main(int argc, char** argv) { 
    std::cout << is_union_or_class1<dummy_type>::value << "\n"; 
    std::cout << is_union_or_class2<dummy_type>::value << "\n"; 
} 

I:ここではテストコードです。

+0

あなたのスペシャライゼーションはさまざまなことをしています - 渡されたパラメータがメンバ変数へのポインタと見なせるタイプであれば最初のテスト、指定したタイプのメンバへのポインタ型を作成できる場合は2番目のテスト、変数... –

+0

Tがメンバーオブジェクトの有効なホストであるかどうかをテストするべきではありませんか? –

+0

いいえ型がメンバーオブジェクトへのポインタかどうかをテストします。 –

答えて

1

はこのことを考えてみましょう:

is_union_or_class1<dummy_type>::value 

dummy_typeはあなたが推測したいTクラスのchar型のデータメンバへのポインタではありません。換言すれば、この専門化はdummy_typeのために破棄されます(私を言います)タイプchar T::*と一致しません。
は、したがって、クラステンプレートが選択され、その一つがstd::false_typeから継承します。このような

template <class T> 
struct is_union_or_class_helper1 : public std::false_type { }; 

何かが働くだろう:

template <class T, typename = T> 
    struct is_union_or_class_helper1 : public std::false_type { }; 
    template <class T> 
    struct is_union_or_class_helper1<T, decltype((char T::*){}, T{})> : public std::true_type { }; 

void_tイディオムの別のバリエーション以外の何物でもないということ。
は、私はそれを少し書き直してみましょう:

template <class T, typename = void> 
    struct is_union_or_class_helper1 : public std::false_type { }; 
    template <class T> 
    struct is_union_or_class_helper1<T, decltype((char T::*){}, void())> : public std::true_type { }; 

をそして、それはそれ、まだC++ 17を待っているもののためvoid_tイディオムの形の一つです。