2010-07-09 11 views
4

Après un certain temps de débogage mon code, je traqué la raison de mes problèmes à certains résultats de spécialisation de modèle inattendu en utilisant enable_if:Comportement étrange de enable_if en utilisant des classes imbriquées (? MSVC bug du compilateur ou fonctionnalité)

Le code suivant échoue l'assertion dans DoTest() dans Visual Studio 2010 (et 2008), alors que ce n'est pas le cas dans g ++ 3.4.5. Cependant, lorsque je supprime le modèle de SomeClass ou de déplacer my_condition hors de la portée de SomeClass il fonctionne aussi en MSVC.

Y at-il un problème avec ce code qui expliquerait ce comportement (au moins partiellement) ou s'agit-il d'un bogue dans le compilateur MSVC?

(en utilisant ce code exemple, il est le même pour stimuler et C++ 0x version stl)

#include <cassert> 
#include <boost\utility\enable_if.hpp> 

template <class X> 
class SomeClass { 
public: 
    template <class T> 
    struct my_condition { 
     static const bool value = true; 
    }; 

    template <class T, class Enable = void> 
    struct enable_if_tester { 
     bool operator()() { return false; } 
    }; 

    template <class T> 
    struct enable_if_tester<T, typename boost::enable_if< my_condition<T> >::type> { 
     bool operator()() { return true; } 
    }; 

    template <class T> 
    void DoTest() { 
     enable_if_tester<T> test; 
     assert(test()); 
    } 
}; 

int main() { 
    SomeClass<float>().DoTest<int>(); 
    return 0; 
} 

Lorsque vous essayez de le corriger en déplaçant la condition hors de la portée, j'ai aussi remarqué que cela ne suffit pas même lorsque vous utilisez std :: enable_if, mais au moins il fonctionne avec boost :: enable_if:

#include <cassert> 
//#include <boost\utility\enable_if.hpp> 
#include <type_traits> 

template <class T, class X> 
struct my_condition { 
    static const bool value = true; 
}; 

template <class X> 
class SomeClass { 
public: 
    template <class T, class Enable = void> 
    struct enable_if_tester { 
     bool operator()() { return false; } 
    }; 

    template <class T> 
    //struct enable_if_tester<T, typename boost::enable_if< my_condition<T, X> >::type> { 
    struct enable_if_tester<T, typename std::enable_if< my_condition<T, X>::value >::type> { 
     bool operator()() { return true; } 
    }; 

    template <class T> 
    void DoTest() { 
     enable_if_tester<T> test; 
     assert(test()); 
    } 
}; 

int main() { 
    SomeClass<float>().DoTest<int>(); 
    return 0; 
} 

J'espère que quelqu'un a une explication pour cela.

+0

Pourriez-vous imprimer un message d'erreur du compilateur? Ou est-ce seulement l'échec d'assertion? – doc

+0

Par curiosité, y a-t-il une raison particulière à ce que enable_if_tester soit une structure plutôt qu'une méthode? – Staffan

+1

@Staffan: Spécialisation partielle. –

Répondre

4

Tout va bien avec votre code, c'est juste que VC est bogué. Il est connu pour avoir des problèmes avec la spécialisation de modèle partiel des classes de membres de modèle.

+0

Merci, je ne m'attendais vraiment pas à un tel bug dans le plus récent VS. Je suppose que je vais mettre quelques assertions statiques dans les spécialisations pour vérifier la condition pour le moment, donc je remarque quand le compilateur est sorti immédiatement. Une solution de contournement fiable qui s'assure que le compilateur fait ce qu'il est censé faire serait plus agréable, cependant. – mfya