【问题标题】:Does `decltype` give me an object's static type, or its runtime type?`decltype` 是给我一个对象的静态类型,还是它的运行时类型?
【发布时间】:2013-03-31 17:33:10
【问题描述】:

[C++11: 7.1.6.2/4]:decltype(e)表示的类型定义如下:

  • 如果e 是未加括号的id-expression 或未加括号的类成员访问(5.2.5),则decltype(e)e 命名的实体的类型。如果不存在这样的实体,或者如果e 命名了一组重载函数,则程序格式错误;
  • 否则,如果e 是xvalue,则decltype(e)T&&,其中Te 的类型;
  • 否则,如果e是左值,decltype(e)就是T&,其中Te的类型;
  • 否则,decltype(e)e 的类型。

decltype 说明符的操作数是未计算的操作数(第 5 条)。

第二、第三和第四种情况明确指的是表达式的类型,不包括任何多态性考虑。

但是,我不完全确定“entity”在这里是什么意思,first 案例似乎是在命名所引用的 object通过表达式e。 “实体的类型”是指它的运行时类型还是它的静态类型,对我来说是模棱两可的。

【问题讨论】:

  • 哦,看!这是“回答你自己的问题”——嫉妒的警察。
  • 别介意他们,出于同样的原因,我被否决了。未来的读者可能想看看this
  • -1,在 C++ 中所有类型都是静态的,并且只存在于编译时。
  • @Abyx:不,“动态类型”存在。也就是说,object 的类型而不是产生访问它的表达式。考虑A* a = new B(),您就会知道*a 所指对象的动态类型 是什么。例如,请参阅[C++11: 10.3/9],其中使用了该术语。
  • 一个更明显的答案:你引用的最后一句话。如果decltype 的操作数没有被求值,那么就没有动态类型这样的东西。 decltype 是编译时评估(如sizeof),因此只能使用静态类型。

标签: c++ c++11 language-lawyer decltype


【解决方案1】:

由于第一种情况的限制,实际上不可能遇到这个问题。

考虑:

struct A     {};
struct B : A {};

int main()
{
   A* x = new B();
   // What is `decltype(*x)`?
}

* 的使用使我们陷入第三种情况。

为了参考?

struct A     {};
struct B : A {};

int main()
{
   A& x = *(new B());
   // What is `decltype(x)`?
}

x 是一个类型为A& 的引用,它是this“实体”的类型结果。

使用第一种情况的唯一方法是直接命名一个对象,我们不能以隐藏运行时类型的方式这样做:

struct A     {};
struct B : A { void foo() {} };

int main()
{
   A x = B();     // well, you've sliced it now, innit?

   decltype(x) y;
   y.foo();       // error: ‘struct A’ has no member named ‘foo’
}

这就是为什么,根据these answers,使用的对象总是静态类型

【讨论】:

  • 在第一个例子中,*x 不会是一个左值(触发第三种情况,而不是第四种情况)?
  • 您的回答在我看来更像是“类型”一词在标准中的含义,当它不是明确的“静态类型”或“动态类型”时,例如 [expr.unary.op ]/1 或在函数调用的“参数类型”中。
  • @DyP:嗯,部分。至少我可以看到你会如何解释它。然而,我只要求decltype的行为考虑到明显的模棱两可,问题标题的内容进一步强化了这一点。
  • @Mankarse:是的,我想会的。
  • 我认为说一个对象具有“静态”类型是没有意义的。一个对象只是有一个类型。 表达式 可以具有静态和动态类型(并且始终具有类型)。静态类型就是它的类型。动态类型(仅适用于 glvalues)是 glvalue 所引用的最衍生对象的类型。
【解决方案2】:

您不必查看各个点:结果 decltype 是编译器已知的类型, 很多不包括任何动态类型。最后一行你 引用再明确不过了:说明符没有被评估, 这也排除了任何动态类型。

【讨论】:

  • the specifier is not evaluated, which also excludes any dynamic typing 我们必须依靠常识,还是在某处声明?
  • 这并不能真正回答问题。可能是 decltype 实际上向 C++ 引入了动态类型(没有具体理由不这么认为)。
  • @Mankarse Occam 的剃须刀却另有说法。
  • @SebastianRedl:奥卡姆剃刀原则未编入标准。
  • @SebastianRedl 我很想说该标准的大部分内容与奥卡姆的剃刀原则相反。然而,在这种情况下,标准将动态类型明确定义为对表达式求值的结果,并且decltype 中的表达式不会被求值。
【解决方案3】:

这基本上是一个“实体”在这里意味着什么的问题(可能的含义在第 3 条中定义)。考虑

struct A {
  int a;
};

int main() {
  A a = {};
  const A b = {};

  const A *aptr = (rand() % 42) ? &a : &b;
  decltype(aptr->a) x = 0;
  decltype((aptr->a)) y = 0;
}

x 的类型是 const int 还是 int?如果您将entity 表示“成员”,则它是int,因为成员A::a 的类型为int。如果您采用实体类型“对象”,则类型为const intint,具体取决于rand() 的结果。对象、它们的存在和属性(包括它们的一般类型)是一个运行时问题。

我说这不是真正的模棱两可。因为每个人都知道是什么意思,并且因为标准使用短语“由 e 命名”而不是“由 e 引用”或“由 e 表示”,表明它只是被查阅的名称查找结果。

注意y的类型总是const int&,因为表达式aptr->a的类型是const int,它是一个左值。

【讨论】:

  • “每个人都知道是什么意思”并不能从本质上解决歧义。它代表了解决歧义的常见尝试。
  • @LightnessRacesinOrbit 我同意。随时进行缺陷报告。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-28
  • 2013-07-14
  • 1970-01-01
  • 2011-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多