2016-10-01 3 views
9

以下のコードは、タイプTにメソッドsortがあるかどうかを正しくチェックしています。しかし、(*)と表示された行をdecltype(&U::sort,...)に変更してdecltype(U::sort,...)(記号&は削除されています)の場合、コードは常にfalseを返します。関数の前にアンパサンド付きのSFINAE関数

なぜですか?

なぜ名前自体では十分ではありませんか?これは&の意味ですか?

#include <iostream> 
#include <type_traits> 

template <typename T> 
class has_sort { 

    template <typename U> 
    static auto check(bool) -> decltype(&U::sort, std::true_type()); // (*) 

    template <typename U> 
    static std::false_type check(...); 

public: 
    using type = decltype(check<T>(true)); 
    static bool const value = type::value; 
}; 

int main() { 
    struct Foo { void sort(); }; 
    struct Foo2 { void sort2(); }; 
    std::cout << "Foo: " << has_sort<Foo>::value << std::endl; 
    std::cout << "Foo2: " << has_sort<Foo2>::value << std::endl; 
    std::cout << "int: " << has_sort<int>::value << std::endl; 
} 

答えて

3

を使用すると、タイプUにメンバーメソッド(静的かどうか)またはデータメンバー(静的かどうか)が含まれているかどうかを総称して確認します。そのための
(あなたも指定子を考慮すれば、他)、それは以下のすべてのタイプと一致します:

  • struct Foo { void sort(); };
  • struct Foo { static void sort(); };
  • struct Foo { int sort; };
  • struct Foo { static int sort; };

反対側では、U::fooはメンバーメソッドを検出するために使用することはできません(たとえあなたがある場合にはデータメンバーを検出するためにそれを使用する)。
template <typename U> static std::false_type check(...);もありますので、sortメンバーメソッドを検出しようとすると、上記の関数の特殊化中のエラーは、sfinaeルールのために黙って破棄され、この1つが選択されます。

sortをより機能的に(静的でもなくても)使用する必要がある場合は、utilityヘッダーを含めてstd:: declvalを使用する必要があります。このように、アンパサンドはもはや必要とされない:

template <typename U> 
static auto check(bool) -> decltype(std::declval<U>().sort(), std::true_type()); // (*) 

このように、データメンバー名sortはもはや検出されません。


私はあなたの提案を与えることができれば、あなたはint/charオーバーロードとconstexpr機能を使って、ビット物事を単純化することができます。一例として、

template <typename T> 
class has_sort { 
    template <typename U> 
    constexpr static auto check(int) -> decltype(std::declval<U>().sort(), std::true_type()) { return {}; } 

    template <typename U> 
    constexpr static std::false_type check(char) { return {}; } 

public: 
    static constexpr bool value = check<T>(0); 
}; 

あなたがC++ 14を使用することができる場合には、テンプレート変数は、よりコンパクトである:それは次のように

template<typename T, typename = void> 
constexpr bool has_sort = false; 

template<typename T> 
constexpr bool has_sort<T, decltype(std::declval<T>().sort(), void())> = true; 

あなたはあなたの例では、それを使用することができます。

std::cout << "Foo: " << has_sort<Foo> << std::endl; 
5

答えは簡単です。&を除いたメンバー関数のアドレスは取得できません。あなた自身のために試すことができません。

auto fun = Foo::sort; // error 

標準の構文は、それなしであいまいになるので、メンバ関数ポインタは、&で使用しなければならないことが必要です。テンプレートにすることを想像して:

template<typename T> 
void test() { 
    T::test2; // is it a member function pointer or static data member? 
} 

のでsfinaeチェックが右である:タイプTsortという名前の静的データメンバーを持っているかどう&せず、チェックがtrueになります。

それはデモンストレーション用である、がしかし、あなたは、このトリックでこの制限を回避でき、私はこれを行うには、あなたをアドバイスしません:

struct Foo { 
    void sortImpl(); 

    static constexpr auto sort = &Foo::sortImpl; 
}; 

その後sortという名前の静的データメンバーのチェックをうそして、sortは関数ポインタになります。

+0

私は2つの回答を受け入れることはできません。ちなみに、アンパサンドのないバージョンは、データメンバ(静的かどうか)だけでなく、静的メソッドにもマッチします。 – olpa

+1

clangもそれを受け入れ、正しいと思います。標準では、「静的メンバー関数(9.4)は通常の関数です。」 – olpa

+0

確かに、静的関数のアンパサンドなしのチェックが正しいかもしれませんが、静的でないメンバー関数には必要です。 –

関連する問題