Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange enable_if behaviour using nested classes (MSVC compiler bug or feature?)

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.

like image 473
mfya Avatar asked Jul 09 '10 00:07

mfya


1 Answers

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.

like image 62
hkaiser Avatar answered Nov 14 '22 05:11

hkaiser