You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用v143工具时模板重载构造函数决议失败问题咨询

为何代码在MSVC v142可正常编译,v143却编译失败?

核心原因:MSVC v143在/permissive-模式下严格遵循C++标准,对继承构造函数的处理做了规范修正,而v142的宽松模式允许非标准行为。


示例1分析

代码:

#include <memory>

namespace H {
    template <typename T>
    struct shared_ptr : public std::shared_ptr<T> {
        using _MyBase = std::shared_ptr<T>;
        using _MyBase::shared_ptr;
    };
}


int main() {
    H::shared_ptr<int> sharedDirectInitializaiton0{ nullptr };
    H::shared_ptr<int> sharedDirectInitializaiton1{ std::shared_ptr<int>{} }; // v143报错C2440
    H::shared_ptr<int> sharedCopyInitialization0 = nullptr;
    H::shared_ptr<int> sharedCopyInitialization1 = std::shared_ptr<int>{}; // v143报错C2440
    return 0;
}

现象:v142编译正常;v143开启/permissive-时编译失败,关闭该选项则恢复正常。

原因:

  1. 当派生类H::shared_ptr<T>通过using _MyBase::shared_ptr;继承基类std::shared_ptr<T>的构造函数时,C++标准规定:基类的非模板拷贝构造函数(std::shared_ptr(const std::shared_ptr&))不会被继承为派生类的拷贝构造函数,而是派生类会隐式生成自己的拷贝构造函数(H::shared_ptr(const H::shared_ptr&))。
  2. 用std::shared_ptr<int>初始化H::shared_ptr<int>属于跨类型构造(基类对象→派生类对象),需要派生类有一个接受const std::shared_ptr<T>&的构造函数——这依赖于继承的基类模板构造函数(template <class Y> std::shared_ptr(const std::shared_ptr<Y>&))。
  3. v142的宽松模式下,编译器会“放宽”规则,允许将基类对象的初始化匹配到继承的模板构造函数;但v143的/permissive-严格模式下,编译器严格执行标准,对模板构造函数的推导和匹配做了更严格的校验,导致无法匹配到合适的构造函数,从而抛出C2440转换错误。

示例2分析

代码:

#include <type_traits>

template <typename T>
struct Base {
    Base() {};
    Base(std::nullptr_t) {}
    
    template <typename U, typename = std::enable_if_t<std::is_convertible<U, T>::value>>
    Base(Base<U>) {}
};

template <typename T>
struct Derived : public Base<T> {
    using _MyBase = Base<T>;
    using _MyBase::_MyBase;
};


int main() {
    // v142与v143均正常
    Derived<int> derived1{ nullptr };
    Derived<int> derived2 = nullptr;

    // v143编译失败,v142正常
    Derived<int> derived3{ Base<int>{} }; // 报错C2440
    Derived<int> derived4 = Base<int>{};  // 报错C2440
    return 0;
}

现象:用nullptr初始化时两个版本均正常;用Base<int>初始化时v143报错。

原因:

  1. Base<T>的模板构造函数template <U> Base(Base<U>),其enable_if条件要求U可转换为T。当用Base<int>初始化Derived<int>时,U会被推导为int,此时std::is_convertible<int, int>::value为true,理论上构造函数应该有效。
  2. v142的宽松模式下,编译器会忽略继承构造函数中的一些模板推导细节,直接匹配该构造函数;但v143的/permissive-模式下,编译器严格校验继承构造函数的模板实例化逻辑:当派生类继承基类的模板构造函数时,该构造函数在派生类中的实例化需要满足更严格的匹配规则,导致编译器无法正确识别Base<int>可以匹配到模板构造函数,从而抛出转换错误。

总结:
MSVC v143的/permissive-模式默认开启,该模式严格遵循C++标准,修正了v142中允许的非标准继承构造函数匹配行为。如果需要兼容旧代码,可以通过关闭/permissive-选项恢复宽松模式,但更推荐的做法是修改代码以符合标准——比如为派生类显式定义所需的构造函数,而非仅依赖继承的基类构造函数。

内容的提问来源于stack exchange,提问作者isrepeat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 13:47:06