2017-07-26 2 views
0

J'essaie actuellement de compiler une structure SFINAE simple avec un compilateur VC++. Ma version (selon la commande cl) estSFINAE avec compilateur VC++

Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x86 

ce code compile bien sur clang

// Example program 
#include <iostream> 
#include <string> 
#include <typeinfo> 

struct spString 
{ 
    template <class... T> 
    spString format(T...) { return spString(); } 
    const char* c_str() { return nullptr; } 

    spString operator+(spString) { return spString(); } 
    spString operator+(const char*) { return spString(); } 
}; 

struct debuggable 
{ 
    spString getDebugString() { return spString(); } 
}; 

void fromFloat(spString, float&) {} 
void fromInt(spString, int&) {} 


template <class T> inline auto from(T v) 
    -> decltype(v.getDebugString(), spString()) 
{ 
    return v.getDebugString(); 
} 
template <class T> inline auto from(T v) 
    -> decltype(v->getDebugString(), spString()) 
{ 
    spString r; 
    r.format("%u (%s)", (size_t) v, v->getDebugString().c_str()); 
    return r; 
} 
template <class T> inline spString from(T v) 
{ 
    return spString("(") + typeid(T).name() + " instance)"; 
} 
template <> inline spString from(float _v   ) { spString _d; fromFloat   (_d, _v); return _d; } 
template <> inline spString from(int _v   ) { spString _d; fromInt   (_d, _v); return _d; } 
//other base types 

int main() 
{ 
    debuggable x{}; 

    from(0); 
    from(0.f); 
    from(x); 
} 

mais échouera sur le compilateur de Microsoft. Non, je ne peux pas utiliser une autre version et je suis coincé avec celui que j'utilise en ce moment. J'ai toujours eu un succès mitigé avec SFINAE sur ce compilateur mais je ne vois pas comment "réparer" facilement ce code. Le résultat attendu est d'obtenir une représentation de chaîne de débogage de quelque chose, si elle a un getDebugString, utilisez cette méthode, si c'est un type de base, utilisez une méthode personnalisée, sinon, imprimez simplement le nom du type.

Voyez-vous un moyen d'y parvenir avec ma version de Visual Studio?

+0

Quels sont l'objet des deux premières surcharges? L'un est pour la méthode renvoyant 'spString' et l'autre pour la méthode retournant' std :: string'? – Holt

+0

Il doit gérer le cas où le type a une méthode getDebugString et l'utiliser à la place de la méthode de repli par défaut – Nyashes

+0

En ce qui concerne edit: std :: string n'est jamais mentionné, nous n'utilisons pas std :: string pour d'anciennes raisons. Aussi l'une des méthodes s'applique sur un pointeur ou un pointeur comme des objets à un objet, l'autre pour diriger des instances – Nyashes

Répondre

1

Voici la façon de faire ce que vous voulez - testé avec VC 19.00.24215.1.

modèle Aide à détecter getDebugString():

template <typename T> 
auto has_getDebugString_impl(int) -> 
    decltype(void(std::declval<T>().getDebugString()), std::true_type{}); 

template <typename T> 
auto has_getDebugString_impl(...) -> std::false_type; 

template <typename T> 
struct has_getDebugString: decltype(has_getDebugString_impl<T>(0)) { }; 

Combiné avec std::enable_if:

template <class T> 
inline std::enable_if_t < has_getDebugString<T>::value, spString > from(T v) { 
    return v.getDebugString(); 
} 

template <class T> 
inline std::enable_if_t < has_getDebugString<T>::value, spString > from(T *v) { 
    spString r; 
    r.format("%u (%s)", (size_t)v, v->getDebugString().c_str()); 
    return r; 
} 
template <class T> 
inline std::enable_if_t < ! has_getDebugString<T>::value, spString > from(T v) { 
    return spString("(") + typeid(T).name() + " instance)"; 
} 

Et surcharge (pas de modèle spécialisé) pour les types spécifiques:

inline spString from(float _v) { spString _d; fromFloat(_d, _v); return _d; } 
inline spString from(int _v) { spString _d; fromInt(_d, _v); return _d; } 

Ce n'est pas le code plus jolie, et il peut y avoir façon plus directe, mais je devais faire face à une question dans VC ...

Note: Vous pouvez utiliser enable_if dans un paramètre de modèle par défaut au lieu d'un type de retour si vous voulez:

template <class T, class = std::enable_if_t<has_getDebugString<T>::value>> 
inline spString from(T v) { 
    return v.getDebugString(); 
} 
+0

merci, désolé, j'ai seulement réussi à trouver un ordinateur maintenant, ce qui est un peu en retard. – Nyashes