2017-06-19 5 views
2

Dans une classe, j'ai deux méthodes différentes qui devraient être mutuellement exclusives en fonction du paramètre de modèle d'appelant.C++ 03: Méthodes mutuellement exclusives grâce à enable_if

class Foo 
{ 
    // For collections 
    template<class T> 
    typename boost::enable_if<boost::is_same<typename std::vector<typename T::value_type>, T>::value, const T&>::type 
    doSomething() 
    { } 


    // For single types 
    template<class T> 
    typename boost::enable_if<!boost::is_same<typename std::vector<typename T::value_type>, T>::value, const T&>::type 
    doSomething() 
    { } 
} 

Ceci ne sera pas compilé.

error: type/value mismatch at argument 1 in template parameter list for 'template struct boost::enable_if' error: expected a type, got '! boost::is_same::value'

+2

Peut-être voulez-vous 'boost :: enable_if_c'? Voir par exemple [la référence Boost enable_if] (http://www.boost.org/doc/libs/1_64_0/libs/core/doc/html/core/enable_if.html). –

+0

pourquoi ne pas utiliser 'disable_if' – danielspaniol

+2

étrange, pourquoi spécifiez-vous' const T & 'avant' doSomething() ', car le type de retour aurait déjà été spécifié par' typename boost :: enable_if ... '? – Alexey

Répondre

-1

Si ce que vous voulez est de surcharger la fonction en fonction de si vous êtes donné un vecteur ou non

#include <type_traits> 
#include <iostream> 
#include <vector> 

using std::cout; 
using std::endl; 

class Foo { 
public: 
    // For collections 
    template <class T> 
    const vector<T>& do_something(const std::vector<T>& input) { 
     cout << __PRETTY_FUNCTION__ << endl; 
     return input; 
    } 


    // For single types 
    template <class T> 
    const T& do_something(const T& input) { 
     cout << __PRETTY_FUNCTION__ << endl; 
     return input; 
    } 
}; 

int main() { 
    auto foo = Foo{}; 
    auto v = std::vector<int>{}; 
    auto i = int{}; 
    foo.do_something(v); 
    foo.do_something(i); 
} 

Si vous voulez être encore plus générale et vérifier pour tout type instancié

#include <type_traits> 
#include <iostream> 
#include <vector> 

using std::cout; 
using std::endl; 

namespace { 

    template <typename T, template <typename...> class TT> 
    struct IsInstantiationOf 
      : public std::integral_constant<bool, false> {}; 
    template <template <typename...> class TT, typename... Args> 
    struct IsInstantiationOf<TT<Args...>, TT> 
      : public std::integral_constant<bool, true> {}; 
} // namespace anonymous 

class Foo { 
public: 
    // For collections 
    template <typename VectorType, typename std::enable_if_t<IsInstantiationOf< 
      std::decay_t<VectorType>, std::vector>::value>* = nullptr> 
    void do_something(VectorType&&) { 
     cout << "Vector overload" << endl; 
    } 

    // For single types 
    template <class T, typename std::enable_if_t<!IsInstantiationOf< 
      std::decay_t<T>, std::vector>::value>* = nullptr> 
    void do_something(T&&) { 
     cout << "Non vector overload" << endl; 
    } 
}; 

int main() { 
    auto foo = Foo{}; 
    auto v = std::vector<int>{}; 
    auto i = int{}; 
    foo.do_something(v); 
    foo.do_something(i); 
} 

s'il vous plaît noter également que vous devriez éviter de mettre std::enable_if dans la signature de la fonction autant que possible pour ces raisons https://stackoverflow.com/a/14623831/5501675

+0

Le type de retour de la fonction est le type T modèle, je ne peux pas le trier avec une simple surcharge de fonction, j'ai besoin de SFINAE – codeJack

+0

@codeJack pour utiliser SFINAE, si c'est ce que vous voulez – Curious

+0

@downvoter pourquoi la downvote? – Curious

1

Que diriez-vous:

template <typename T> struct is_std_vector : std::false_type {}; 
template <typename T, typename A> 
struct is_std_vector<std::vector<T, A>> : std::true_type {}; 

Et puis

class Foo 
{ 
    // For collections 
    template<class T> 
    typename std::enable_if<is_std_vector<T>::value, const T&>::type 
    doSomething(); 

    // For single types 
    template<class T> 
    typename std::enable_if<!is_std_vector<T>::value, const T&>::type 
    doSomething(); 
}; 
+0

Cela fonctionne un peu. Mais pourquoi ne pourrais-je pas utiliser ma propre syntaxe sans avoir besoin de définir une structure is_std_vector? – codeJack

+1

'T :: value_type' n'est pas défini pour tout type, donc vous SFINAE également sur cela, et c'est incorrect pour la plupart des types non-conteneur. – Jarod42

0

Contrairement à la version std, boost::enable_if accepte un type (wrapper un peu sous la valeur booléenne), de sorte que vous devriez écrire quelque chose comme

class Foo 
{ 
    // For collections 
    template<class T> 
    typename boost::enable_if< 
     typename boost::is_same<typename std::vector<typename T::value_type>, T>, 
    const T&>::type doSomething() 
    { } 


    // For single types 
    template<class T> 
    typename boost::enable_if_с< 
     !boost::is_same<typename std::vector<typename T::value_type>, T>::value, 
    const T&>::type doSomething() 
    { } 
} 

Notez ici, j'ai utilisé typename avant boost::is_same et n'ont pas utilisé ::value dans la première spécification. Au contraire, j'ai dû utiliser enable_if_с dans la deuxième surcharge, car l'opérateur ! n'est pas applicable à un type.

0

Qu'en est-il de la répartition des étiquettes?

#include <vector> 
#include <iostream> 

template <typename, typename> 
struct isSame 
{ typedef int type; }; 

template <typename T> 
struct isSame<T, T> 
{ typedef long type; }; 

struct foo 
{ 
    template <typename T> 
    T const & doSomething (T const & t, int) 
    { std::cout << "int version" << std::endl; return t; } 

    template <typename T> 
    T const & doSomething (T const & t, long) 
    { std::cout << "long version" << std::endl; return t; } 

    template <typename T> 
    T const & doSomething (T const & t) 
    { return doSomething(t, typename isSame< 
     typename std::vector<typename T::value_type>, T>::type()); } 
}; 

int main() 
{ 
    foo f; 
    std::vector<int> v; 
    f.doSomething(v); // print "long version" 
}