2015-12-21 7 views
7

Do wykrywania członków w C++ 14 Użyłem kodu opartego na przykładzie here, ale to nie wydaje się działać.Detekcja członka za pomocą void_t

Kompletny przykład:

#include <string> 

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

template <typename, typename = void> class HasMember_substr : public std::false_type {}; 
template <typename T> class HasMember_substr<T, void_t<typename T::substr>> : public std::true_type {}; 

template <typename, typename = void> class HasMember_fff : public std::false_type {}; 
template <typename T> class HasMember_fff<T, void_t<typename T::fff>> : public std::true_type {}; 

static_assert(HasMember_substr<std::string>::value, ""); 
static_assert(!HasMember_fff<std::string>::value, ""); 

int main() { return 0; } 

Zestawione użyciu clang++ --std=c++14 test.cpp na OS X, wersja kompilatora (clang++ --version): Apple LLVM version 7.0.2 (clang-700.1.81)

Drugi assert powiedzie, ale pierwsza zawiedzie. Czemu? Próbowałem również używać decltype(T::substr) zamiast typename T::subset, z tym samym wynikiem.

+2

'T :: substr' to nie to samo co' T {}. Substr' –

+1

Czy 'substr' jest przeciążoną funkcją w twojej implementacji? (Mogło tak być). – aschepler

+1

Skopiowałeś przykład testowania dla typu i spodziewałeś się, że ten sam kod zadziała w testowaniu dla funkcji składowej. To oczywiście nie zadziała. 'std :: string :: substr' nie jest typem, więc' typename T :: substr' jest oczywiście nonsensem. Powinieneś skopiować przykład, który testuje pre-inkrementację. –

Odpowiedz

11

Poszukiwanie T::substr to nie to samo co szukanie funkcji składowej o nazwie substr. gcc.godbolt.org example

Można sprawdzić, czy funkcja elementu istnieje, używając std::declval<T>() i korzystając z decltype, aby uzyskać typ zwracanej funkcji składowej.

Jeśli funkcja elementu istnieje, decltype(...) będzie dobrze sformułowanym wyrażeniem i nie wyzwoli SFINAE - dlatego static_assert będzie działał poprawnie.

#include <string> 
#include <type_traits> 
#include <utility> 

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

template <typename, typename = void> 
class HasMember_substr : public std::false_type {}; 

template <typename T> 
class HasMember_substr<T, void_t< 
    decltype(std::declval<T>().substr(1, 1))> 
> : public std::true_type {}; 

static_assert(HasMember_substr<std::string>::value, ""); 

int main() { return 0; } 

Zauważ, że decltype(std::declval<T>().substr(1, 1)) sprawdza, czy T posiada substr element, który może być wywołana z argumentami 1, 1. (to nie gwarantuje się funkcję użytkownika, może to być również element danych funktor, np.)


Jak wspomniano przez AndyG w komentarzach, innym z możliwych rozwiązań jest użycie decltype do "sprawdzanie poprawności" typu wskaźnika funkcji członka.

Przykład:

HasMember_substr<T, void_t< decltype(&T::substr)> 

Należy pamiętać, że to nie będzie działać, jeśli nazwa substr jest przeciążony, a is not guaranteed to work with any type in the standard library.

+1

Mogę uprościć jako 'HasMember_substr ' – AndyG

+0

@AndyG: dobry punkt. Dodawanie rozwiązania do odpowiedzi. –

+5

@AndyG to nie zadziała, jeśli nazwa 'substr' jest przeciążona –

Powiązane problemy