10

[C++11: 7.1.6.2/4]: The type denoted by decltype(e) is defined as follows:

  • if e is an unparenthesized id-expression or an unparenthesized class member access (5.2.5), decltype(e) is the type of the entity named by e. If there is no such entity, or if e names a set of overloaded functions, the program is ill-formed;
  • otherwise, if e is an xvalue, decltype(e) is T&&, where T is the type of e;
  • otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;
  • otherwise, decltype(e) is the type of e.

The operand of the decltype specifier is an unevaluated operand (Clause 5).

The second, third and fourth cases clearly refer to the type of the expression, which would not include any polymorphism considerations.

However, and I'm not entirely sure what "entity" means here, the first case appears to be naming the object refered to by the expression e. It is ambiguous to me as to whether "the type of the entity" means its runtime type, or its static type.

Lightness Races in Orbit
  • 358,771
  • 68
  • 593
  • 989
  • 2
    Oh, look! It's the "answer your own question"-jealousy police. – Lightness Races in Orbit Apr 09 '13 at 10:23
  • 3
    Don't mind them, I got downvoted for the same reason. Future readers may want to have a look at [this](http://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/). – Andy Prowl Apr 09 '13 at 10:30
  • 1
    Self-answered questions specially about forgotten issues of a programming language deserve **up-votes** not down-votes. – masoud Apr 09 '13 at 10:32
  • 1
    @LightnessRacesinOrbit Many SO users are not aware of " [**It’s OK to Ask and Answer Your Own Questions**](http://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/) " ... – Grijesh Chauhan Apr 09 '13 at 10:33
  • 5
    -1, in C++ all types are static and exist only in compile time. – Abyx Apr 09 '13 at 10:36
  • 3
    @Abyx: No, "dynamic types" exist. That is, the type of the _object_ rather than the expression that yields access to it. Consider `A* a = new B()` and you know what the _dynamic type_ of the object referred to by `*a` is. See `[C++11: 10.3/9]` for example, where this term is used. – Lightness Races in Orbit Apr 09 '13 at 10:39
  • @didierc: Then where are the close-as-dup votes? That's right, there are none, because this is not a duplicate. – Lightness Races in Orbit Apr 09 '13 at 10:40
  • 1
    [Quoting @Abyx in chat](http://chat.stackoverflow.com/transcript/message/8750558#8750558): _"meh... the Standard is just wrong then."_ – Lightness Races in Orbit Apr 09 '13 at 10:43
  • 9
    An even more obvious answer: the last sentence you quote. If the operand of `decltype` is not evaluated, there is no such thing as dynamic type. `decltype` is a compile time evaluation (like `sizeof`), and so can only use the static type. – James Kanze Apr 09 '13 at 11:06
  • 1
    @james whether there is evaluation or not is irrelevant. If the type of an object is to be determined, it better be evaluated, otherwise the determination is impossible. But saying "because it is impossible to determine X, we say that X for our purpose is Y" is not good. – Johannes Schaub - litb Apr 09 '13 at 18:37
  • 1
    @andy i dont agree that the type of objects are determined always at compile time. Consider `new int[rand ()% 5]` where the type of the object is only known at runtime. – Johannes Schaub - litb Apr 09 '13 at 19:00
  • @Johannes: Maybe you intended to reply to Abyx? – Andy Prowl Apr 09 '13 at 19:01
  • @andy i was reading the chat history – Johannes Schaub - litb Apr 09 '13 at 19:04
  • 1
    @JohannesSchaub-litb: So the type of the object created by `new int[rand ()% 5]` is known only at run-time and information about it is inaccessible, is it so? – Andy Prowl Apr 09 '13 at 19:07
  • Also see https://groups.google.com/forum/m/?fromgroups#!topic/comp.std.c++/M6CCezr6VkU . However note that i do not agree anymore that it is a defect - "class member" is the right entity and does not include the const. – Johannes Schaub - litb Apr 09 '13 at 19:13
  • @JohannesSchaub-litb: I'm too dumb to understand how that relates to your previous example :( – Andy Prowl Apr 09 '13 at 19:30
  • @JohannesSchaub-litb The type of an object is determined when the object is created. The type of a declaration is determined at compile time; `decltype` is part of a declaration. – James Kanze Apr 10 '13 at 08:03

3 Answers3

8

It's actually impossible to run into this problem, due to the restraints of that first case.

Consider:

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

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

The use of * makes us fall through to the third case.

And for references?

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

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

x is a reference with type A&, and it is this "entity" whose type results.

The only way to use the first case is by directly naming an object, and we cannot do that in a way that hides a runtime type:

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’
}

This is why, according to these answers, it is always the static type of an object that is used.

Community
  • 1
  • 1
Lightness Races in Orbit
  • 358,771
  • 68
  • 593
  • 989
  • In the first example, wouldn't `*x` be an _lvalue_ (triggering the third case, rather than the fourth)? – Mankarse Apr 09 '13 at 10:45
  • Your answer looks to me like the question is rather what the term "type" means in the standard, when it's not explicitly "static type" or "dynamic type", like [expr.unary.op]/1 or in "types of the arguments" for function calls. – dyp Apr 09 '13 at 11:22
  • @DyP: Well, partially. I can see how you might interpret it that way, at least. However, I _am_ asking solely for `decltype`'s behaviour _given that apparent ambiguity_, as re-inforced by the content of the question's title. – Lightness Races in Orbit Apr 09 '13 at 11:25
  • @Mankarse: Yes, I think it would. – Lightness Races in Orbit Apr 09 '13 at 11:26
  • There's no apparent (or real) ambiguity. The contexts in which `decltype` can be used exclude any possible dynamic typing, as does the last line quoted in the question. – James Kanze Apr 09 '13 at 11:27
  • @JamesKanze: Isn't that precisely what I said in my answer? – Lightness Races in Orbit Apr 09 '13 at 11:29
  • you can do `x->a`, which is a member access expression (part of the first bullet). `x` can be `const X`. then the type of the object (object is an entity kind) is `const MemberType`. You cannot know that at compile time. (`x` can be a pointer that points to either an object of type `X` or `const X` - note that the type of the expression `x` is irrelevant). – Johannes Schaub - litb Apr 09 '13 at 16:49
  • I have asked this question before on usenet - basically you have the choice between the entity kind "member"/"variable" or "object". It is not mentioned explicitly, but i think if you take "member" (or "variable"), you get to choose the static declared type and everything is fine (a "member" is something declarative - as opposed to a "member subobject", which is a runtime relation relating a subobject to its parent membering object). the type of an object is a runtime property, so obviously this cannot be the intended kind of entity referred to by the Standard. – Johannes Schaub - litb Apr 09 '13 at 16:51
  • @JohannesSchaub-litb For expressions, doesn't the Std define what the "type of an expression" is? Like [expr.ref], though I'm not entirely sure to what extent `a->m` is covered as opposed to `a.m`. – dyp Apr 09 '13 at 16:59
  • @DyP see below at my answer. – Johannes Schaub - litb Apr 09 '13 at 17:05
  • 4
    I don't think that it make sense to say that an object has a "static" type. An object simply has a type. An *expression* can have a static and a dynamic type (and always has a type). A static type is simply its type. And a dynamic type (only for glvalues) is the type of the most derived object to which the glvalue refers. – Johannes Schaub - litb Apr 09 '13 at 17:08
  • @JohannesSchaub-litb Yes. The distinction between static type and dynamic type is only relevant to an expression. It doesn't apply elsewhere (e.g. in a declaration). – James Kanze Apr 10 '13 at 08:05
6

You don't have to look into the individual points: the results of decltype are a type known to the compiler, which pretty much excludes any dynamic typing. And the last line that you quote couldn't be more explicit: the specifier is not evaluated, which also excludes any dynamic typing.

James Kanze
  • 142,482
  • 15
  • 169
  • 310
  • `the specifier is not evaluated, which also excludes any dynamic typing` Do we have to rely on common sense for this, or is it stated someplace? – Lightness Races in Orbit Apr 09 '13 at 11:26
  • 1
    This doesn't really answer the question. It could be that `decltype` actually introduces dynamic typing to C++ (without specific reason to think otherwise). – Mankarse Apr 09 '13 at 11:31
  • @Mankarse Occam's razor says otherwise, though. – Sebastian Redl Apr 09 '13 at 12:06
  • 1
    @SebastianRedl: Occam's Razor is not codified in the standard. – Lightness Races in Orbit Apr 09 '13 at 12:23
  • @LightnessRacesinOrbit Maybe the basic meaning of "dynamic"? The standard defines how dynamic resolution takes place (depending on the run-time type of the object), which makes it clear that it cannot be done at compile time. – James Kanze Apr 09 '13 at 12:45
  • 2
    @SebastianRedl I'm tempted to say that large parts of the standard are contrary to Occam's razor. In this case, however, the standard clearly defines dynamic typing as a result of evaluating an expression, and that the expression in `decltype` is not evaluated. – James Kanze Apr 09 '13 at 12:47
  • I think you would agree with my answer below. – Johannes Schaub - litb Apr 09 '13 at 18:15
0

It's basically a question of what "entity" means here (the possible meanings are defined in clause 3). Consider

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;
}

Is x's type const int or int? If you take entity to mean "member", it is int because the member A::a has type int. If you take the entity kind "object", then the type is either const int or int, depending on the result of rand(). Objects, their existence and properties (including their type in general) is a runtime issue.

I say that this is not a real ambiguity. Because everyone knows what is meant and because the Standard uses the phrase "named by e" rather than "referred to by e" or "denoted by e" indicating that it is only the name lookup result that it is consulted.

Note that the type of y is always const int&, because the type of the expression aptr->a is const int and it is an lvalue.

Johannes Schaub - litb
  • 466,055
  • 116
  • 851
  • 1,175