我正在尝试使用MSVC在Windows上编译Flusspferd,但由于模板实例化问题而失败。为了便于解释,我用简单的术语重写了这个问题:
#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)
{
}
};
问题是,TestClass包含一个模板化构造函数,它使用boost :: is_convertible和转发类UndefinedType。 is_convertible仅适用于完整类型,这意味着只有在定义了UndefinedType时才应使用此构造函数,否则模板实例化将因C2139而失败。
在Flusspferd中,TestClass用于尚未定义UndefinedType但使用其他构造函数的地方:
void test()
{
A* a = new A();
TestClass test(a); // will instantiate the templated constructor, but why?
}
虽然TestClass(A * a)是这种情况下最具体的构造函数,但由于is_convertible,模板将被实例化,导致C2139。
GCC汇编很好,所以问题是:为什么不是MSVC?谁是对的?有办法解决这个问题吗?
感谢您的帮助!
更新
MSalters是对的。正确的行为是未定义的。从C ++ - 标准:
如果重载解析过程可以在不实例化类模板定义的情况下确定要调用的正确函数,则未指定该实例化是否实际发生。
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
};
答案 0 :(得分:2)
正如您所说,“is_convertible仅适用于完整类型”。这意味着如果违反此前提条件,则可能发生任何事情 - 特别是未定义的行为。所以GCC和MSVC都是“正确的” - 他们既没有义务生成工作代码也没有错误。