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

为何C++17中std::pair异构“移动”构造函数的显式性发生变化?

std::pair构造函数explicit特性的版本差异解析

先看问题中的代码示例:

#include <memory>
#include <utility>

using X = std::unique_ptr<int>;

using A = std::pair<int, const X>;
using B = std::pair<int,       X>;

static_assert(std::is_constructible<A, B>::value, "(1)"); // 合法
static_assert(std::is_convertible<B, A>::value, "(2)"); // C++14及以前被GCC和Clang拒绝

static_assert(std::is_constructible<const X, X>::value, "(3)"); // 合法
static_assert(std::is_convertible<X, const X>::value, "(4)"); // 合法

核心现象

在C14及更早版本中,libstdc和libc的实现里,std::pair<int, const std::unique_ptr<int>>从std::pair<int, std::unique_ptr<int>>右值构造的构造函数是explicit的,导致std::is_convertible<B, A>::value为false;而C17起该构造函数变为隐式,MSVC的标准库实现则始终将其设为隐式。

差异来源与C++14中explicit的原因

  1. C++14标准的规则歧义
    在C++14及之前的标准中,std::pair的模板构造函数(对应cppreference的构造函数(6))的explicit属性定义存在歧义:标准描述中,构造函数是否为explicit取决于成员类型的转换特性,但并未明确区分“从右值构造const成员”这类场景的处理逻辑。

libstdc和libc的实现者将此规则解读为:当构造pair<T1, T2>时,若T2是const U2,即使U2可以隐式转换为const U2,pair的模板构造函数仍需标记为explicit——这是对标准规则的保守解读,导致了代码中(2)断言在C++14及以前被拒绝。

  1. C++17的标准修正
    C17标准明确了std::pair模板构造函数的explicit判定规则:仅当U1无法隐式转换为T1,或U2无法隐式转换为T2时,构造函数才会被标记为explicit。由于std::unique_ptr<int>可以隐式转换为const std::unique_ptr<int>,因此pair<B>到pair<A>的构造函数在C17及以后变为非explicit,is_convertible<B, A>::value也变为true。

  2. MSVC的实现差异
    MSVC的标准库实现没有遵循libstdc++/libc对C14规则的保守解读,而是始终按照“成员可隐式转换则构造函数非explicit”的逻辑实现,因此在所有版本中该构造函数都是隐式的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 18:27:32