views:

34

answers:

1

Hello, I am trying to compile Flusspferd on Windows using MSVC, but it fails due to a template instantiation problem. For the ease of explanation I rewrote the problem in simpler terms:

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_convertible.hpp>

class UndefinedType;

class A
{

};

class TestClass {

public:

    TestClass(A* a)
    {

    }

    template<typename OtherType>
    TestClass(OtherType t, typename boost::disable_if<typename boost::is_convertible<OtherType, UndefinedType>::type>::type * = 0)
    {

    }
};

The problem is, that TestClass contains a templated constructor that uses boost::is_convertible with the forwarded class UndefinedType. is_convertible only works for complete types, meaning that this constructor should only be used when UndefinedType has been defined, otherwise the template instantiation will fail with C2139.

In Flusspferd the TestClass is used in places where UndefinedType has not been defined, but using its other constructor:

void test()
{
    A* a = new A();
    TestClass test(a); // will instantiate the templated constructor, but why?
}

Though TestClass(A* a) is the most specific constructor for this situation, the template will be instantiated leading to C2139 because of is_convertible.

GCC compiles fine, so the question is: why isn't MSVC? Who is right? Is there a way to get around this?

Thanks for the help!

Update:

MSalters is right. The correct behaviour is undefined. From the C++-Standard:

If the overload resolution process can determine the correct function to call without instantiating a class template definition, it is unspecified whether that instantiation actually takes place.

template <class T> struct S {
    operator int();
};

void f(int);
void f(S<int>&);
void f(S<float>);

void g(S<int>& sr) {
    f(sr);  // instantiation of S<int> allowed but not required
            // instantiation of S<float> allowed but not required
};
+2  A: 

As you state, "is_convertible only works for complete types". This means that if you violate this precondition, anything can happen - in particular undefined behavior. So both GCC and MSVC are "right" - they're neither obliged to produce working code nor an error.

MSalters