Take the 2-minute tour ×


auto x = initializer;

equivalent to

decltype(initializer) x = initializer;


decltype((initializer)) x = initializer;

or neither?

share|improve this question

4 Answers 4

up vote 25 down vote accepted

decltype also considers whether the expression is rvalue or lvalue .

Wikipedia says,


#include <vector>
int main()
    auto c = 0;           // c has type int
    auto d = c;           // d has type int

That pretty much explains the imporant difference. Notice decltype(c) and decltype((c)) are not same!

And sometime auto and decltype works together in a cooperative way, such as in the following example (taken from wiki, and modified a bit):

int& foo(int& i);
float foo(float& f);

template <class T>
auto f(T& t) −> decltype(foo(t)) 
  return foo(t);

Wikipedia further explains the semantics of decltype as follows:

Similarly to the sizeof operator, the operand of decltype is unevaluated. Informally, the type returned by decltype(e) is deduced as follows:

  • If the expression e refers to a variable in local or namespace scope, a static member variable or a function parameter, then the result is that variable's or parameter's declared type
  • If e is a function call or an overloaded operator invocation, decltype(e) denotes the declared return type of that function
  • Otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e; if e is an rvalue, the result is T

These semantics were designed to fulfill the needs of generic library writers, while at the same time being intuitive for novice programmers, because the return type of decltype always matches the type of the object or function exactly as declared in the source code. More formally, Rule 1 applies to unparenthesized id-expressions and class member access expressions. For function calls, the deduced type is the return type of the statically chosen function, as determined by the rules for overload resolution. Example:

const int&& foo();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1; // type is const int&&
decltype(i) x2; // type is int
decltype(a->x) x3; // type is double
decltype((a->x)) x4; // type is const double&

The reason for the difference between the latter two invocations of decltype is that the parenthesized expression (a->x) is neither an id-expression nor a member access expression, and therefore does not denote a named object.Because the expression is an lvalue, its deduced type is "reference to the type of the expression", or const double&.

share|improve this answer
The wikipedia text isn't correct anymore: decltype(operator-expression) doesn't look at the statically declared return type anymore in the FDIS. –  Johannes Schaub - litb Jul 29 '11 at 12:16

This won't work (and is ugly):

decltype([]() { foo(); }) f = []() { foo(); };


auto f = []() { foo(); };


share|improve this answer
+1. Good difference. :-) –  Nawaz Jul 29 '11 at 8:17

It depends. auto and decltype serve different purposes so they don't map one-to-one.

The rules for auto are the easiest to explain because they are the same as for template parameter deduction. I won't expand on them here, but note that auto& and auto&& are also some possible uses!

decltype however has several cases, some of which you have illustrated above (information and quotes taken from n3290, Simple type specifiers [dcl.type.simple]) that I separate into two categories:

  • when using what the Standard calls "an unparenthesized id-expression or an unparenthesized class member access"
  • the rest!

Informally, I'd say that decltype can operate on either names (for the first case) or expressions. (Formally and according to the grammar decltype operates on expressions, so think of the first case as a refinement and the second case as a catch-all.)

When using a name with decltype, you get the declared type of that entity. So for instance decltype(an_object.a_member) is the type of the member as it appears in the class definition. On the other hand, if we use decltype( (an_object.a_member) ) we find ourselves in the catch-all case and we're inspecting the type of the expression as it would appear in code.

Accordingly, how to cover all the cases of your questions:

int initializer;
auto x = initializer; // type int
// equivalent since initializer was declared as int
decltype(initializer) y = initializer;

enum E { initializer };
auto x = initializer; // type E
// equivalent because the expression is a prvalue of type E
decltype( (initializer) ) y = initializer;

struct {
    int const& ializer;
} init { 0 };
auto x = init.ializer; // type int
// not equivalent because declared type is int const&
// decltype(init.ializer) y = init.ializer;
// not equivalent because the expression is an lvalue of type int const&
// decltype( (init.ializer) ) y = init.ializer;
share|improve this answer
  1. If initializer is an array then decltype(x) or decltype((x)) don't work simply on it. However auto will be deduced to a pointer.
  2. If initializer is a function then applying decltype(fp) will deduce to the function type however, auto will deduce to its return type.

So in general auto cannot be considered as a replacement of any decltype() version you asked.

share|improve this answer
@downvoter please care to explain. Have I state anything wrong ? –  iammilind Jul 29 '11 at 13:23
I did not downvote, but in your second point, you mention that type of var in auto var = f (where f is int f()) is int. However, since you didn't call the function, the actual type of var is int (*)(). And decltype(f()) will indeed resolve to int. See it here. –  Vitus Jul 29 '11 at 16:33
@Vitus, I have mentioned decltype(f) and not decltype(f()); and I had checked it before posting it. See demo: ideone.com/fIh13; still this downvote is not justified; it's sad. :( –  iammilind Jul 29 '11 at 16:45
Yes, but you cannot compare auto a = f(); (where you call the function) and decltype(f) a; (where you do not). That was point of my first comment. –  Vitus Jul 29 '11 at 16:49
you are saying that auto x = printf would be int. But that's not the case at all. What @Vitus said. Not sure what that ideone code is meant to demonstrate. –  Johannes Schaub - litb Jul 29 '11 at 23:03

Your Answer


