2015-12-21 13 views
7

Per il rilevamento dei membri in C++ 14 ho utilizzato il codice basato sull'esempio here, ma sembra che non funzioni.Rilevamento dei membri utilizzando void_t

Un esempio completo:

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

compilato utilizzando clang++ --std=c++14 test.cpp su OS X, versione del compilatore (clang++ --version): Apple LLVM version 7.0.2 (clang-700.1.81)

La seconda asserzione riesce, ma la prima non riesce. Perché? Ho anche provato a utilizzare decltype(T::substr) anziché typename T::subset, con lo stesso risultato.

+2

'T :: substr' non è lo stesso di' T {}. Substr' –

+1

'substr' è una funzione sovraccaricata nella vostra implementazione? (È consentito che sia.) – aschepler

+1

Hai copiato un esempio di test per un tipo e si aspetta che lo stesso codice funzioni per testare una funzione membro. Ovviamente non funzionerà. 'std :: string :: substr' non è un tipo, quindi' typename T :: substr' è ovviamente senza senso. Dovresti aver copiato l'esempio che prova per il pre-incremento. –

risposta

11

In cerca di T::substr non è la stessa cosa di cercare una funzione membro denominata substr. gcc.godbolt.org example

È possibile controllare se una funzione di membro esiste utilizzando std::declval<T>() e utilizzando decltype per ottenere il tipo di ritorno della funzione membro.

Se la funzione membro esiste, decltype(...) sarà un'espressione ben formata e non attiverà SFINAE, pertanto il static_assert funzionerà correttamente.

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

Nota che decltype(std::declval<T>().substr(1, 1)) controlla se T ha un membro substr che può essere chiamato con argomenti 1, 1. (Questo non è garantito essere una funzione membro, potrebbe anche essere un membro di dati funtore, per esempio.)


Come detto da AndyG nei commenti, un altro possibile approccio utilizza decltype a "convalida" il tipo di un puntatore a funzione membro.

Esempio:

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

Si noti che questo non funzionerà se il nome substr è sovraccarico, e is not guaranteed to work with any type in the standard library.

+1

Potrei semplificare come 'HasMember_substr ' – AndyG

+0

@AndyG: buon punto. Aggiunta della soluzione alla risposta. –

+5

@AndyG questo non funzionerà se il nome 'substr' è sovraccarico –

Problemi correlati