我正在尝试编译 Flusspferd在 Windows 上使用 MSVC,但由于模板实例化问题而失败。为了便于解释,我用更简单的术语重写了问题:
#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 包含一个模板构造函数,该构造函数使用带有转发类 UndefinedType 的 boost::is_convertible。 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
};
最佳答案
正如您所说,“is_convertible 仅适用于完整类型”。这意味着如果你违反了这个先决条件,任何事情都可能发生——尤其是未定义的行为。所以 GCC 和 MSVC 都是“正确的”——它们既没有义务生成工作代码也没有错误。
关于c++ - MSVC : Implicit Template Instantiation, 虽然未使用模板化构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3387991/