std::pair分段构造函数如何识别元组中的右值引用?
关于std::pair分段构造中模板推导与右值引用的解析
你的核心误解在于模板参数推导的匹配规则,下面详细拆解整个过程:
1. 模板参数的精确匹配逻辑
当你传入std::tuple<int&&, int&&>作为实参,匹配std::pair分段构造函数的std::tuple<Args2...>形参时,模板推导会优先选择精确匹配:
- 不会将
int&&退化(decay)为int来构造std::tuple<int, int> - 直接推导
Args2...为int&&, int&&,让std::tuple<Args2...>完全匹配实参类型
这是因为模板推导的核心原则是:能精确匹配就不做隐式转换或类型调整。
2. 分段构造的参数转发行为
std::pair的分段构造函数内部,会通过std::apply(或等效的转发逻辑)将tuple中的参数传递给Foo的构造函数。由于tuple中存储的是int&&类型的引用,转发时会保留右值引用的属性,最终触发Foo(int&&, int&&)构造函数,所以你会看到"constructor with rvals called"的输出。
3. 你的假设错误点
你误以为Args2会被推导为int,本质是混淆了两种不同的模板推导场景:
- 类型退化(比如把
T&&退化为T)仅发生在直接用模板类型参数接收值传递参数的场景(如template<typename T> void func(T t)) - 而这里的形参是
std::tuple<Args2...>,属于模板实例化后的具体容器类型,推导时会严格匹配实参的tuple内部元素类型
相关代码回顾
Foo类定义:
class Foo { public: Foo(int& a, int& b) { std::cout << "constructor with lvals called\n"; /* ... */ } Foo(int&& a, int&& b) { std::cout << "constructor with rvals called\n"; /* ... */ } // ... };
创建pair的代码:
std::pair<int, Foo> myPair{std::piecewise_construct, std::forward_as_tuple(1), std::forward_as_tuple(2, 3)};
std::forward_as_tuple签名:
template< class... Types > tuple<Types&&...> forward_as_tuple( Types&&... args )
std::pair分段构造函数签名:
template< class... Args1, class... Args2 > constexpr pair( std::piecewise_construct_t, std::tuple<Args1...> first_args, std::tuple<Args2...> second_args );
内容的提问来源于stack exchange,提问作者11thHeaven
相关产品推荐
相关产品推荐

