关于《C++ Primer 第5版》第711页remove_reference示例中decltype(i)类型判断的正确性问询
关于《C++ Primer 第5版》第711页
decltype(i)类型的疑问与验证 你的判断完全正确!《C++ Primer》这里确实存在表述上的不准确,我们可以结合C++标准中decltype的规则和你的测试代码来明确这一点。
先明确C++标准中decltype的核心规则
- 当操作数是标识符表达式(id-expression,比如单个变量名
i)时,decltype直接返回该标识符的声明类型——也就是你定义i时写的int,而非引用类型。 - 只有当操作数是可作为左值的非标识符表达式(比如解引用
*pi、后缀自增i++这类),或者是被括号包裹的标识符(比如decltype((i)))时,decltype才会返回左值引用类型。
针对书中错误点的验证
书中称
decltype(i)是int&,会匹配remove_reference<T&>的偏特化模板,但这不符合C++标准的规则。
你的测试代码完美验证了这一点,我们再把代码和运行结果整理一下:
测试代码
#include <iostream> #include <string> #include <typeinfo> using namespace std; template <typename T> struct blubb { typedef T type; void print() { cout << "plain argument type\n"; } }; template <typename T> struct blubb<T&> { typedef T type; void print() { cout << "lvalue reference type\n"; } }; template <typename T> struct blubb<T&&> { typedef T type; void print() { cout << "rvalue reference type\n"; } }; int main() { int i = 0; blubb<decltype(42)> plain; plain.print(); blubb<decltype(i)> lvalue_ref; // 实际并非左值引用类型! lvalue_ref.print(); int* pi = &i; blubb<decltype(*pi)> lvalue_ref2; // 可作为左值的表达式 lvalue_ref2.print(); blubb<decltype(std::move(i))> rvalue_ref; rvalue_ref.print(); return 0; }
编译运行命令
g++ -o types types.cpp -Wall -pedantic -g && ./types
运行结果
plain argument type plain argument type lvalue reference type rvalue reference type
结果分析
blubb<decltype(42)>:42是右值字面量,decltype返回int,匹配通用模板,输出plain argument typeblubb<decltype(i)>:i是标识符表达式,decltype返回int,匹配通用模板,输出plain argument type——这直接证明了你的观点,书中此处的描述错误blubb<decltype(*pi)>:*pi是左值表达式(解引用指针得到的是左值),decltype返回int&,匹配左值引用偏特化,输出lvalue reference typeblubb<decltype(std::move(i))>:std::move(i)返回int&&右值引用,decltype返回int&&,匹配右值引用偏特化,输出rvalue reference type
如果书中想要展示左值引用偏特化的使用场景,正确的例子应该是decltype((i))——括号包裹的标识符属于表达式,此时decltype会返回int&,这才会匹配blubb<T&>的偏特化模板。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

