MSVC:隐式模板实例化,但未使用模板构造函数

Posted

技术标签:

【中文标题】MSVC:隐式模板实例化,但未使用模板构造函数【英文标题】:MSVC: Implicit Template Instantiation, though templated constructor not used 【发布时间】:2010-08-02 13:01:54 【问题描述】:

我正在尝试使用 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 用于未定义未定义类型但使用其​​其他构造函数的地方:

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
;

【问题讨论】:

这个结构应该实现什么? 【参考方案1】:

正如您所说,“is_convertible 仅适用于完整类型”。这意味着如果您违反此前提条件,任何事情都可能发生——尤其是未定义的行为。所以 GCC 和 MSVC 都是“正确的”——它们既没有义务产生工作代码也没有错误。

【讨论】:

以上是关于MSVC:隐式模板实例化,但未使用模板构造函数的主要内容,如果未能解决你的问题,请参考以下文章

C++坑点集合 - 1 隐式调用和默认实现的构造函数的坑

struct 中不可访问的模板化构造函数

Vue构造器及其实例化概念

类中移动构造函数的位置/顺序很重要?与移动构造函数结合使用的模板化强制转换运算符

如何防止特定模板的隐式模板实例化?

继承构造函数是不是适用于 C++0x 中的模板?