我正在尝试更好地理解 decltype ,以便在编译时确定表达式的类型。比方说,我用双变量来做:
#include <iostream>
#include <type_traits>
int main(){
double a;
typedef decltype(a) a_type;
typedef decltype((a)) ref_a_type;
typedef decltype(a)& o_ref_a_type;
a_type b;
ref_a_type c = b;
o_ref_a_type d = b;
if (std::is_same<decltype(b), double>::value) std::cout << "b is double\n";
if (std::is_same<decltype(c), double&>::value) std::cout << "c is double&\n";
if (std::is_same<decltype(d), double&>::value) std::cout << "d is double&\n";
}
如果我理解正确,这些要点应该是真的:
decltype(a)
是左值,则double&
会返回a
,否则会返回double
。 因此,decltype((a))
和decltype(a)&
在这种情况下是等效的,但并不总是等效的,例如,如果a
不是变量:
typedef decltype((5)) ref_a_type;
typedef decltype(5)& o_ref_a_type;
然后两种类型都不相等(ref_a_type
是int
而o_ref_a_type
是int&
,因为在这种情况下,额外的括号是无用的)。有人可以给出更好的解释吗?我应该使用第一种还是第二种方式?
IMO似乎比第一种方式更具可读性和可理解性。
答案 0 :(得分:6)
就C ++标准而言,decltype(e)
的规则非常清楚,所以我只是复制它们(来自[dcl.type.simple]):
对于表达式
e
,decltype(e)
表示的类型定义如下:
(4.1) - 如果e
是未加密码的 id-expression 或未加密码的类成员访问(5.2.5),decltype(e)
是e
命名的实体的类型。如果没有这样的实体,或者e命名一组重载函数, 该计划格式不正确;
(4.2) - 否则,如果e
是xvalue,decltype(e)
是T&&
,其中T
是e
的类型;
(4.3) - 否则,如果e
是左值,decltype(e)
是T&
,其中T
是e的类型;
(4.4) - 否则,decltype(e)
是e
的类型。
按顺序浏览你的例子:
decltype(a)
:a
是未加密码的 id-expression ,因此这只是a
的类型:double
。decltype((a))
:现在它有了括号,所以我们跳过了第一颗子弹。 a
不是xvalue,它是左值,所以这是double&
。decltype(a)&
:这只是第一个案例,所以它是double&
。decltype((5))
:这既不是 id-expression (带括号或其他),xvalue或左值 - 所以我们放到最后一个项目符号来获取表达式:int
。decltype(5)&
:与最后一点相同,除非您现在明确添加&
,所以int&
。我应该使用第一种还是第二种方式?
这取决于您实际想要获得的类型。这两种方式意味着不同的东西 - 你应该用任何一种方法来解决你试图解决的直接问题。
更一般地说,由于参考折叠规则,decltype(expr)&
总是左值参考。
decltype((expr))
可以是非引用(与decltype((5))
一样),左值引用(与decltype((a))
一样),也可以是右值引用(与decltype((std::move(a)))
一样)