74

As I understand it, both decltype and auto will attempt to figure out what the type of something is.

If we define:

int foo () {
    return 34;
}

Then both declarations are legal:

auto x = foo();
cout << x << endl;

decltype(foo()) y = 13;
decltype(auto)  y = 13; // alternatively, since C++14
cout << y << endl;

Could you please tell me what the main difference between decltype and auto is?

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
James Leonard
  • 3,593
  • 5
  • 27
  • 32
  • 2
    @JesseGood Before asking the question, I read that thread and am looking for a cleaner explanation – James Leonard Aug 23 '12 at 02:50
  • 1
    Similar questions: [1]: http://stackoverflow.com/questions/11459928/equivalence-between-decltype-and-auto [2]: http://stackoverflow.com/questions/6869888/the-relationship-between-auto-and-decltype – Sujith Surendranathan Aug 23 '12 at 02:50
  • 1
    @JamesLeonard: Okay, well I don't know a better explanation [than the one by Scott Meyers](http://cpp-next.com/archive/2011/04/appearing-and-disappearing-consts-in-c/). – Jesse Good Aug 23 '12 at 02:54
  • Clearly explained by Scott Meyers in youtube.com/watch?v=wQxj20X-tIU&t=1468s – RajeshDA Sep 01 '20 at 17:12

6 Answers6

73

decltype gives the declared type of the expression that is passed to it. auto does the same thing as template type deduction. So, for example, if you have a function that returns a reference, auto will still be a value (you need auto& to get a reference), but decltype will be exactly the type of the return value.

#include <iostream>
int global{};

int& foo()
{
   return global;
}
 
int main()
{
    decltype(foo()) a = foo(); //a is an `int&`
 // decltype(auto)  a = foo();   alternatively, since C++14

    auto b = foo(); //b is an `int`
    b = 2;
    
    std::cout << "a: " << a << '\n'; //prints "a: 0"
    std::cout << "b: " << b << '\n'; //prints "b: 2"
    std::cout << "---\n";

    decltype(foo()) c = foo(); //c is an `int&`
 // decltype(auto)  c = foo();   alternatively, since C++14
    c = 10;
    
    std::cout << "a: " << a << '\n'; //prints "a: 10"
    std::cout << "b: " << b << '\n'; //prints "b: 2"
    std::cout << "c: " << c << '\n'; //prints "c: 10"
 }

Also see David Rodríguez's answer about the places in which only one of auto or decltype are possible.

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
Mankarse
  • 39,818
  • 11
  • 97
  • 141
50

This is a C++11 answer to a C++11 question

auto (in the context where it infers a type) is limited to defining the type of a variable for which there is an initializer. decltype is a broader construct that, at the cost of extra information, will infer the type of an expression.

In the cases where auto can be used, it is more concise than decltype, as you don't need to provide the expression from which the type will be inferred.

auto x = foo();                           // more concise than `decltype(foo()) x`
std::vector<decltype(foo())> v{ foo() };  // cannot use `auto`

The keyword auto is also used in a completely unrelated context, when using trailing return types for functions:

auto foo() -> int;

There auto is only a leader so that the compiler knows that this is a declaration with a trailing return type. While the example above can be trivially converted to old style, in generic programming it is useful:

template <typename T, typename U>
auto sum( T t, U u ) -> decltype(t+u)

Note that in this case, auto cannot be used to define the return type.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • I compiled this code without decltype and it worked fine. gave correct type. – Žarko Tomičić May 18 '23 at 17:09
  • @ŽarkoTomičić: Yes, this is a somewhat outdated answer to an old question. The answer is correct in C++11, but C++14 introduced *return type deduction* and now you can use `auto f() { return ; }` with the compiler deducing the type of the function from the body – David Rodríguez - dribeas Jul 05 '23 at 11:12
3

That's my thinking about the auto and decltype:

The most obvious difference in pratice between the two is:

  • In type deduction for expr, decltype deduce the correct type( except the lvalue expr -> lvalue ref) and auto default to value.

We need to learn the "data stream" model before understanding the difference.

In our codes, the function calling can be resolved as a data stream model(something like the concept of functional program), so the function which is been called is the data receiver, and the caller is the data provider. It is obviously that the data type must be decided by the data receiver, or the data cannot be organized in order in the data stream.

Look this:

template<typename T>
void foo(T t){
    // do something.
}

the T will be deduced to a value type, regardless of whether you pass. If you want the ref type, you should use auto& or auto&&, that's what I am saying, the data type is decided by the data receiver.

Let's return to the auto:

auto is used to do a type deduction for rvalue expr, giving the data receiver a correct interface to receive the data.

auto a = some expr; // a is data receiver, and the expr is the provider.

So why dose auto ignore the ref modifier? because it should be decided by the receiver.

Why we need decltype?

The answer is : auto cannot to be used as a true type deduction, it will not give you the correct type of a expr. It just give the data receiver a correct type to receive the data.

So, we need decltype to get the correct type.

ACCTSO
  • 49
  • 5
0

Generally, if you need a type for a variable you are going to initialize, use auto. decltype is better used when you need the type for something that is not a variable, like a return type.

Ankur
  • 1,385
  • 11
  • 21
0

modify @Mankarse's example code,I think a better one blew:

#include <iostream>
int global = 0;
int& foo()
{
   return global;
}

int main()
{
    decltype(foo()) a = foo(); //a is an `int&`
    auto b = foo(); //b is an `int`
    b = 2;

    std::cout << "a: " << a << '\n'; //prints "a: 0"
    std::cout << "b: " << b << '\n'; //prints "b: 2"
    std::cout << "global: " << global << '\n'; //prints "global: 0"

    std::cout << "---\n";

    //a is an `int&`
    a = 10;

    std::cout << "a: " << a << '\n'; //prints "a: 10"
    std::cout << "b: " << b << '\n'; //prints "b: 2"
    std::cout << "global: " << global << '\n'; //prints "global: 10"

    return 0;

}
J.Doe
  • 319
  • 1
  • 8
0

I consider auto to be a purely simplifying feature whereas the primary purpose of decltype is to enable sophisticated metaprogramming in foundation libraries. They are however very closely related when looked at from a language-technical point of use.

From HOPL20 4.2.1, Bjarne Stroustrup.

Yaokun Xu
  • 64
  • 5