2017-07-18 4 views
0

J'ai une classe, qui enveloppe une énumération et fournit une conversion de chaîne pour celle-ci. Maintenant, j'ai introduit le paramètre de modèle 'fastStringConvert' qui contrôle comment la conversion faite en utilisant SFINAE (trouvé ici: how can I use std::enable_if in a conversion operator?). Le code compile sous MSVC, mais échoue sous GCC et Clang.SFINAE pour l'opérateur de casting

error: no type named ‘type’ in ‘struct std::enable_if<false, void>’ 

Quel pourrait être le problème et comment dois-je changer le code?

Les parties pertinentes du code ci-dessous ou ici: http://rextester.com/SYC74124

#include <map> 
#include <string> 
#include <type_traits> 

template < 
    class SubClass, 
    typename EnumType, 
    bool fastStringConvert = true 
> 
class SmartEnum 
{ 
public: 
    template < 
     typename SFINAEPostponer = EnumType, 
     typename = typename std::enable_if<fastStringConvert, void>::type 
    > 
    explicit operator const std::string&() const 
    { 
     auto name = SubClass::names().find((int)value); 
     if (name != SubClass::names().end()) 
     { 
      return name->second; 
     } 
     else 
     { 
      static const std::string na("n.a."); 
      return na; 
     } 
    } 

    template < 
     typename SFINAEPostponer = EnumType, 
     typename = typename std::enable_if<!fastStringConvert, void>::type 
    > 
    explicit operator const std::string() const 
    { 
     auto name = SubClass::names().find((int)value); 
     if (name != SubClass::names().end()) return name->second; 
     else return std::to_string((int)value); 
    } 

protected: 
    typedef const std::map<int, std::string> Names; 
    EnumType value; 
}; 


enum class Foo_type : int { a, b, c }; 

struct Foo : SmartEnum<Foo, Foo_type, true> 
{ 
    typedef SmartEnum<Foo, Foo_type, true> Base; 

    static const Base::Names &names() 
    { 
     static const Base::Names names = { { 0, "a" }, { 1, "b" }, { 2,"c" }}; 
     return names; 
    } 
}; 

Répondre

2

Vous devez utiliser l'argument de modèle à partir de la méthode, sinon vous avez une erreur matérielle, quelque chose comme:

template < 
    typename SFINAEPostponer = EnumType, 
    bool Cond = !fastStringConvert, 
    typename = typename std::enable_if<Cond, void>::type 
> 
explicit operator const std::string() const 

BTW , mieux vaut utiliser enable_if comme type au lieu de la valeur par défaut (pour autoriser la désactivation de la partie):

template < 
    typename SFINAEPostponer = EnumType, 
    bool Cond = !fastStringConvert, 
    typename std::enable_if<Cond, void>::type* = nullptr 
> 
explicit operator const std::string() const 
+0

T Hanks, ça a aidé. Je n'ai même pas besoin du premier argument de cette façon. – simon

+0

Pourriez-vous expliquer quelle est la différence entre cette solution? – simon

+0

@simon vous ne pouvez pas surcharger une fonction uniquement en fonction de la valeur par défaut du paramètre template, tout comme vous ne pouvez pas surcharger la fonction sur la base de la valeur par défaut de son paramètre. –