2016-01-27 1 views
1

J'essaie de faire ce qui suit: une classe basée sur un modèle devrait fournir certaines fonctions selon que le type avec lequel elle a été gérée contient ou non une variable membre avec un nom donné. A titre d'exemple le pseudo-code suivant qui devrait fournir "printid()" seulement quand templated struct/classe a un membre appelé "id":C++: fournir une fonction de classe dans une classe modélisée sur l'existence d'un membre nommé dans son type de modèle?

#include <iostream> 
#include <type_traits> 

struct A { int id; }; 
struct B { }; 

template<typename T> 
class foo 
{ 
    T myvar; 

public: 
    #if exists T.id (or the alternative: #if exists myvar.id) 
    printid() { std::cout << "I have element id."; } 
    #endif 
}; 

int main(){ 
    foo<A> ok; 
    ok.printid(); // should compile and execute 

    foo<B> nok; 
    nok.printid(); // should not compile 
    return 0; 
} 

En fouillant SFINAE, traits, std :: enable_if et StackOverflow, je pense que peut être fait ... en quelque sorte. Mais je ne en quelque sorte de combiner enable_if avec le l'extrait suivant de la question How to detect whether there is a specific member variable in class?:

template<typename T, typename = void> 
struct has_id : std::false_type { }; 

template<typename T> 
struct has_id<T, decltype(std::declval<T>().id, void())> : std::true_type { }; 

Toute aide appréciée.

Répondre

3

Oui, c'est possible. Voici un exemple:

template<typename T> 
class foo 
{ 
    T myvar; 

public: 
    template <class _T = T, 
      class = typename std::enable_if< 
         !std::is_function<decltype(_T::id)>::value> 
        ::type> 
    void printid() { std::cout << "I have element id."; } 
}; 

Plus précisément, notez la façon dont nous « prendre en » T comme _T afin de ne pas forcer une contrainte sur le paramètre de modèle de classe (ce qui rendrait la classe elle-même non compilable) . Au lieu de cela, nous créons une nouvelle fonction de membre de modèle indépendante, qui ne force rien sur T lui-même — il "l'arrive" à l'utiliser comme argument par défaut. C'est la partie clé.

+1

Fonctionne comme prévu. Je n'aurais jamais découvert comment déclarer ce vaudou. Envelopper ceci dans une définition pour enregistrer la frappe pour plusieurs fonctions est maintenant un morceau de gâteau. Merci beaucoup. – BaCh