views:

52

answers:

1

After quite some time debugging my code, I tracked down the reason for my problems to some unexpected template specialization results using enable_if:

The following code fails the assertion in DoTest() in Visual Studio 2010 (and 2008), while it doesn't in g++ 3.4.5. However, when i remove the template from SomeClass or move *my_condition* out of the scope of SomeClass it works in MSVC, too.

Is there something wrong with this code that would explain this behaviour (at least partially) or is this a bug in the MSVC compiler?

(using this example code it's the same for boost and the c++0x stl version)

#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;
}

When trying to fix it by moving the condition out of the scope, i also noticed that this isn't even enough when using std::enable_if, but at least it works with 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;
}

I hope someone has an explanation for this.

+2  A: 

Everything is fine with your code, it's just that VC is buggy. It's known to have problems with partial template specialization of template member classes.

hkaiser
Thanks, I really didn't expect such a bug in the most recent VS. I guess I'll put some static assertions into the specializations to double check condition for now, so i notice when the compiler crapped out immediately. A reliable workaround that makes sure the compiler does what it is expected to do would be nicer, though.