2016-10-01 23 views
9

Aşağıdaki kod, T türünün sort yöntemine sahip olup olmadığını doğru olarak denetler. Ancak, 'u decltype(U::sort,...) (& sembolü kaldırılır) değiştirerek (*) işaretli satırı değiştirdiğimde, kod her zaman false döner.SFINAE işlevi ile bir işlev isminden önce ve aşağıdaki isimle

Neden?

Neden adın kendisi yeterli değil? Bu & ne anlama geliyor?

#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; 
} 

cevap

3

&U::foo kullanarak, genel olarak U türünde bir üye yöntemi (statik veya değil) veya bir veri üyesi (statik veya değil) içerip içermediğini kontrol edersiniz. (Ayrıca belirteçleri göz önüne alırsak, ve diğerleri) Bu nedenle
, tüm aşağıdaki türde eşleşir:

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

Diğer taraftan, U::foo üye yöntemlerini algılamak için kullanılamaz. Bazı durumlarda veri üyelerini tespit etmek için hala bir kullanım).
Yine de, sort üye yöntemini saptamaya çalıştığınızda, template <typename U> static std::false_type check(...); hizmetinizdedir, yukarıdaki işlev özelleştirme sırasında hata sfinae kuralları nedeniyle sessizce atılır ve bu bir tanesi alınır.

Daha katı olmak ve (statik veya değil olarak) bir işlev olarak sort zorunlu tutmak istiyorsanız

, sen utility başlığı içermesi ve bunun yerine std:: declval kullanmalıdır.Bu şekilde, ve işareti artık gereklidir:

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

Bu şekilde, veri üyeleri isimleri sort artık algılanmaz.


Sana bir öneri verebilir varsa, int/char aşırı yüklenmesini ve constexpr işlevleri kullanarak biraz ortalığı kolaylaştırabilir. Örnek olarak
:

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 kullanabiliyorsa, şablon değişkenleri daha kompakt şunlardır: aşağıdaki gibi

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; 

Sen örnekte kullanabilirsiniz:

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

cevabı basittir: & olmadan üye fonksiyonunun adresini alamaz. Kendin için deneyemezsin:

auto fun = Foo::sort; // error 

standart sözdizimi onsuz belirsiz olacağından üye işlev işaretçisi, & kullanılmalıdır gerektirir. Bir şablonda düşünün:

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

Yani sfinae onay haklı: tip T sort adında bir statik veri üyesi olurdu eğer & olmadan, çek geçerli olacak.

Ancak, bu gösteri amaçlı olup, her ne kadar bu numara ile bu sınırlamayı atlatabilir ve ben bunu yapmak değil tavsiye ediyorum:

struct Foo { 
    void sortImpl(); 

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

Sonra sort adında bir statik veri üyesi için onay olurdu Doğru ve sort bir işlev işaretçisi olur.

+0

Yazık İki cevap kabul edemiyorum. Bu arada, ampersand-free sürümü sadece bir veri üyesi (statik değil) değil aynı zamanda statik bir yöntemle de eşleşiyor. – olpa

+1

clang da bunu kabul ediyor ve bence doğru. Standart diyor ki: "Bir statik üye işlevi (9.4) sıradan bir işlevdir." – olpa

+0

Gerçekten de, denetim, statik işlev için ampersan olmadan doğru olabilir, ancak statik olmayan üye işlevleri için gereklidir. –

İlgili konular