2011-05-08 117 views
13

(由an answer提示。)什么是decltype(0 + 0)?

鉴于N3290,§7.1.6.2p4,这里的列表项是无编号,但编号在这里为我们的方便:

通过decltype表示的类型(E )被定义为如下:

  1. 如果e是一个括号的ID-表达或加括号的类的成员访问(5.2.5),decltype(e)是通过e命名实体的类型。如果没有这样的实体,或者如果e名称是一组重载函数,则该程序是不合格的;如果e是x值,则decltype(e)是T & &,其中T是e的类型;否则,如果e是左值,则decltype(e)是T &,其中T是e的类型;如果e是左值,则decltype(e)是T &,其中T是e的类型;
  2. 否则,decltype(e)是e的类型。

decltype(0 + 0)指定的类型是什么?

第1项不适用,2可能,但如果不适用,则3不适用,4将是结果。那么,什么是xvalue,是0 + 0还是xvalue?

§3.10p1:

的x值(一个“到期”值)也指一个对象,通常接近其寿命的末尾(使得其资源可以被移动,例如)。 xvalue是涉及右值引用的某些表达式的结果(8.3.2)。

我没有在§8.3.2中看到任何有用的东西,但我知道“0 + 0”不涉及任何右值引用。文字0是一个prvalue,它是“不是一个xvalue的右值”(§3.10p1)。我相信“0 + 0”也是一个价值。如果是这样,“decltype(0 + 0)”将是int(不是int & &)。

我错过了我的解释?这段代码是否合格?

decltype(0 + 0) x; // Not initialized. 

代码在GCC 4.7.0 20110427和Clang 2.9(中继线126116)上编译。例如,如果decltype指定了一个int & &类型,那么它将不会完好。

+3

我没有看到你的推理有什么问题。我相信'decltype(0 + 0)'也应该是'int'。 – 2011-05-08 00:36:00

+1

FWIW,肯定的一个好的答案是扩展xvalue的定义并展示它的可能和不可能。 (我会发现*非常有用)。我需要看看如何重新说明,关注“什么是xvalue?”同时仍然考虑这个“0 + 0”的具体情况。 – 2011-05-08 00:43:00

+3

虽然最新的草案确实为很多表达式指定了_value category_,包括后缀增量和3.10中的一个注释,表明第5条应该显示每个内置操作符的值的类别,但似乎没有提到草案任何二元运算符的值类别从5.6到5.15,除非我的搜索能力让我失败。 – 2011-05-08 00:58:33

回答

2

从5.19 [expr.const],每常量表达式是prvalue 。

常量表达式是文本类型的prvalue核心常量表达式,但是没有指针类型。 积分常量表达式是积分或非范围枚举类型的文字常量表达式。

因此规则4适用于所有文字常量表达式。

+0

谢谢,虽然我仍然在“int n = 42; decltype(0 + n)”的语义中看到了一个漏洞(正如Charles在对该问题的评论中指出的)。 :( – 2011-06-03 02:00:15

+0

@Fred:当然,虽然标准清楚地表明'0 + 0'是一个*核心常量表达式*,它的* prvalue *状态仍然存在疑问。显然,如果它不是* prvalue *它不能是一个整型常量表达式,并且很多东西会被打破 – 2011-06-03 02:02:26

+2

你有这个倒退:该段落是**定义**术语*文字常量表达式* – 2012-03-21 06:40:05

0

GCC说int -

代码:

#include <iostream> 
#include <typeinfo> 

int 
main() 
{ 
    int n; 
    decltype(0 + 0) x; 
    std::cout << "Type of `n': " << typeid(n).name() << std::endl; 
    std::cout << "Type of `x': " << typeid(x).name() << std::endl; 
} 

输出:

编辑:根据第4点它是有道理的,但我不能肯定地说第2点实际上并不是实际的效果。根据我所知,0 + 0评估为0,而0的类型为int,因此这是已声明的类型。

+1

但是它对int &&和int类似:http:// ideone .com/6c6N6 – 2011-05-08 00:51:29

+0

的确如此。请注意,对于GCC,int &&与int相同。毕竟,对int的引用是一个int。毕竟,参考只是理论上的一个别名。尝试'if(typeid(int)== typeid(int &&)){std :: cout <<“int == int &&”<< std :: endl; }'。即使它们的字符串是相同的,实际的typeid也不会相同,除非它们被完全对待。这让我想知道它下面发生了什么......现在,我会说'decltype(0 + 0)'产生'int'类型。 – 2011-05-08 01:11:35

2

您的推理是正确的。仅涉及常量的表达式本身就是一个常量。因此

decltype(0 + 0) x; 

等于

decltype(0) x; 

其等于

int x; 
+1

这不回答这个问题。使用零是一个占位符,并且一个好的答案将显示如何推断decltype(some_int + another_int)(或显示为什么零文字是特殊的)。 – 2011-05-10 09:14:28

9

0 + 0是二prvalues的表达,(n3290参数3.10),其适用于内置operator+,其中,每13.6/12是LR operator+(L,R),这是一个返回非参考值的函数。表达的结果也是一个价值(按3.10)。

因此,0 + 0的结果是一个prvalue,0是int,因此0 + 0的结果是一个int

+2

§13.6p9是*一元*运算符+。你需要§13.6p12。然而,草案指出:“这些候选职能参与13.3.1.2中描述的运营商重载决策过程,并且不得用于其他目的。” (§13.6p1)我认为“没有其他目的”意味着我们不能用它们来确定价值类别。无论如何,+1是一个很好的答案。 – 2011-05-08 02:59:41

+0

@FredNurk - 我编辑了参考。我一定很累...... – rlc 2011-05-08 03:07:33

+3

内置的运算符不是函数调用。所以你不能拿13.6/12并得到这些候选者的描述返回类型,并将它们应用回第5条。那些13.6的候选者只有在重载解析时才是有效的和相关的(如果至少有一个操作数是类或枚举类型的)。它们仅用于转换类类型操作数。在完成之后,控制完全返回到第5节。“LR操作符+”不是实际调用的函数。 – 2011-05-12 05:02:31

5

这绝对是一个int:

#include <iostream> 
#include <typeinfo> 

template<typename T> 
struct ref_depth 
{ 
     enum { value = 0 }; 
}; 

template<typename T> 
struct ref_depth<T&> 
{ 
     enum { value = 1 }; 
}; 

template<typename T> 
struct ref_depth<T&&> 
{ 
     enum { value = 2 }; 
}; 

int main() { 

    std::cout 
    << "int: " << typeid(int).name() << "\n" 
     "decltype(0 + 0): " << typeid(decltype(0 + 0)).name() << "\n" 
     "int&&: " << typeid(int&&).name() << "\n"; 
    std::cout 
    << "ref_depth: int: " << ref_depth<int>::value << "\n" 
     "ref_depth: decltype(0 + 0): " << ref_depth<decltype(0 + 0)>::value << "\n" 
     "ref_depth: int&&: " << ref_depth<int&&>::value << "\n"; 

} 

输出:

int: i 
decltype(0 + 0): i 
int&&: i 
ref_depth: int: 0 
ref_depth: decltype(0 + 0): 0 
ref_depth: int&&: 2 
+2

您能否在答案中包含代码? (而不是总结代码在答案中的结论并链接到一个完全不同的网站。) – 2011-05-08 03:21:24

+1

@Fred Nurk:我已经自由了。 – 2011-05-08 05:20:25

相关问题