C++11: ‘decltype’

decltype is a new keyword that infers the type of a given expression. Though it can be used instead of auto; it is used mainly on return types.

For example; this function:

int sum(int a, int b)
{
  typedef int ret;
  ret x = a + b;
  return x;
}

could be written using decltype:

int sum(int a, int b)
{
  typedef decltype(a+b) ret;
  ret x = a + b;
  return x;
}

The compiler evaluates ‘a+b’ and infers the type of such expression is ‘int’ and defines ‘ret’ as an ‘int’.

Useful? In the case shown above: Not at all.

But what if I would want the compiler to infer the return type of my method shown above?. What if I say:

auto sum(int a, int b)  //does not compile!!!
{
  return a + b;
}

Though it is apparently correct, ‘auto’ is not supported on return types; so, this example does not compile.

What if I decide to use decltype:

decltype(a+b) sum(int a, int b) //does not compile!!!
{
  return a + b;
}

Though the decltype usage shown in the example above is correct and worked in the earlier example; in this case it does not compile because when parsing the ‘decltype(a+b)’ thing, the compiler does not know what ‘a’ and ‘b’ are.

To solve this problem, in C++0x there is a new way to declare functions and methods:

auto sum(int a, int b) -> int
{
  return a + b;
}

In the example shown above, with the ‘auto’ keyword you are saying to the compiler that the return type will be specified later, and “later” means after the ‘->’. Using this syntax, you can use decltype to specify the return type:

auto sum(int a, int b) -> decltype(a+b)
{
  return a + b;
}

Useful? With my example, it is still not useful at all; however, the new syntax lets you use the decltype in more complex function declarations and the new syntax is also useful to declare ‘lambda expressions’.

decltype becomes really useful when it is used with templates.

Consider a method template called ‘execute’ that receives as parameters the pointer to the function to execute and a value to pass to such function:

template <class T, class F> //does not compile
??? execute(const T& val, F func)
{
  return func(val);
}

what would be the return type of that function? I want to use it with these functions:

string getname(int x)
{
  switch (x)
  {
    case 0: return "zero";
    case 1: return "one";
    case 2: return "two";
  }
  return "I need to learn to count";
}

and

int getlength(const string& s)
{
  return s.length();
}

I would want to use my ‘execute’ function in this way:

cout << execute("hello", getlength) << endl;
cout << execute(1, getname) << endl;

To solve this problem, we can declare our method template using decltype:

template <typename T, typename F>
auto execute(const T& t, F func) -> decltype(func(t))
{
  return func(t);
}

So in this case, decltype is very very useful and without it maybe implementing this kind of things would be impossible.

Advertisement

5 thoughts on “C++11: ‘decltype’

  1. nicely explained :) in the post u talk about using the decltype with lambdas could you kindly add an example of that?

    thanks i love such articles where by way of examples effective instruction is achieved :)

    1. Thanks awhan for your nice comments.

      About using decltype with lambda expressions, you can explicitly mark the return type of your lambda expression.

      Consider this example:

      class Chloride { };
      
      class Salt { };
      
      class Sodium
      {
      	public:
      		Salt operator+(const Chloride& x) const
      		{
      			return Salt();
      		}
      		
      };
      
      ostream& operator<<(ostream& os, const Salt&)
      {
      	os << "Salt";
      	return os;
      }
      
      template <typename T>
      void show(const T& t)
      {
      	cout << t() << endl;
      }
      
      int main()
      {
      	Sodium na;
      	Chloride cl;
      	
      	show([na, cl]() -> decltype(na + cl)
      	{
      		return na + cl;
      	});
      	return 0;
      }
      

      Look at the show() invocation, you are passing it a lambda expression and defining explicitly its return type.

  2. Hey, thanks for taking the time to write this down. However, I want to add that the last example you give is a bit odd in the sense that you neither need ‘decltype’ nor ‘auto’ to achieve this task. In fact, you can rewrite the execute template as follows (which compiles without using any features of the C++11 standard).

    // template <typename ArgType, typename FunType>
    // auto execute(ArgType arg, FunType fun) -> decltype(fun(arg)) {
    //   return fun(arg);
    // }
    
    template <typename ArgType, typename RetType>
    RetType execute(ArgType arg, RetType (*fun)(ArgType)) {
      return fun(arg);
    }
    
    1. Hi Michael. Thanks for your comment.

      Yes, your implementation works perfectly without using any C++11 features but it will only work with function pointers, not with functors or lambda expressions.

      Am I correct?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s