CTAD中的类型推导与引用折叠规则疑问
C++类型推导与引用折叠的困惑
我对C++的类型推导(type deduction)与引用折叠(reference collapsing)规则存在基础理解困惑。我定义了一个模板类entity,其构造函数接收右值引用参数,且有一个同类型的成员变量。根据引用折叠规则:
- A& & 变为 A&
- A& && 变为 A&
- A&& & 变为 A&
- A&& && 变为 A&&
当我将xvalue(通过std::move(a))绑定到构造函数的Alloc&&参数时,按理解Alloc应被推导为右值引用,但实际运行显示类成员的类型是值类型而非推导的右值引用,对此我感到不解。
测试代码
#include <memory> #include <cstdio> #include <type_traits> template <typename Alloc> struct entity { entity(Alloc&& alloc) : alloc_{ alloc } {} auto print() { if constexpr (std::is_rvalue_reference_v<Alloc>) { printf("Is type is &&"); } else if constexpr (std::is_lvalue_reference_v<Alloc>) { printf("Is type is &"); } else { printf("Is type value"); } } Alloc alloc_; }; int main() { std::allocator<int> a; entity e(std::move(a)); e.print(); }
运行输出
Is type value
问题核心:转发引用的推导规则
你代码里的Alloc&&是转发引用(forwarding reference,又称万能引用),而非普通右值引用,这是导致推导结果不符合预期的关键:
- 当模板参数是
T&&且T是待推导的模板参数时,这属于转发引用场景,推导规则会根据实参类型动态调整T:- 若传入左值(比如直接传
a),T会被推导为左值引用std::allocator<int>&,结合引用折叠,T&&最终变为std::allocator<int>& - 若传入右值(比如
std::move(a)生成的xvalue),T会被推导为非引用类型std::allocator<int>,此时T&&就是std::allocator<int>&&
- 若传入左值(比如直接传
你的代码中,Alloc被推导为std::allocator<int>(值类型),而非右值引用类型,因此成员变量alloc_的类型是值类型,print()自然输出"Is type value"。
验证与修正
如果想让Alloc被推导为右值引用类型,可显式指定模板参数:
// 显式指定Alloc为右值引用类型 entity<std::allocator<int>&&> e(std::move(a));
此时print()会输出"Is type is &&"。
若要让构造函数真正接收普通右值引用而非转发引用,可将模板参数改为非推导上下文,或直接使用非模板类:
// 非模板类,构造函数接收右值引用 struct entity { entity(std::allocator<int>&& alloc) : alloc_(std::move(alloc)) // 此处需用std::move避免拷贝 {} void print() { printf("Is type is &&"); } std::allocator<int> alloc_; };
内容的提问来源于stack exchange,提问作者glades
相关产品推荐
相关产品推荐

