Skip to content

decltype and declval

October 25, 2011

With the decltype keyword, we can now determine the type of an arbitrary expression. For a trivial example, we could write:

decltype(a+b) c = a+b;

although we can already do that with auto. A more interesting use is inside a class definition. Taking the example from my previous post on auto, if we were inside a function we could simply write the following:

std::vector<std::pair<int, std::string>> array;
auto iter = array.begin();

but that doesn’t work if you’re declaring variables inside a class. Instead of typing out the full name of the type of the iterator, you can use decltype:

class A 
  std::vector<std::pair<int, std::string>> array;
  decltype(array.begin()) iter;

This works because decltype doesn’t actually execute the expression given as its argument—it is only used by the type checker to determine a type.

We can also use decltype, along with auto to make determining a function’s return type easier. Suppose that we had a function which took a template argument that is a container, and we were to return an iterator into that container, we could write:

template <typename C>
foo(const C& c)
  -> decltype(c.begin()) 
  //something that returns an iterator
  //it doesn't have to be c.begin(), as long as it
  //is the right type

We could have also done the above example with declval. The template class declval creates a default constructed type of its argument for use in type checking. However, since it can only be used in unevaluated expressions, and therefore is not evaluated, it doesn’t actually create a default constructed object, the type doesn’t even need a default constructor, and in fact, it can be used with an incomplete type. Typically it is used with decltype, since decltype doesn’t evaluate its argument. The above example could be rewritten as:

template <typename C>
decltype(std::declval<const C>().begin())
second(const C& c)
  //do something with c

Note that you must include <utility> to use declval.

  1. madoxster permalink

    What is the official name for this ‘->’ construct:

    auto foo(const C& c) -> decltype(c.begin()) { … }

    can ‘->’ only be used that way with ‘auto’?

    • The whole construct: -> type is called a trailing return type. I don’t know if the arrow itself has a name. I’m pretty sure that the only place it can be used like that is with auto. The standard says at

      1 The auto type-specifier signifies that the type of a variable being declared shall be deduced from its initializer
      or that a function declarator shall include a trailing-return-type.
      2 The auto type-specifier may appear with a function declarator with a trailing-return-type (8.3.5) in any
      context where such a declarator is valid.

Trackbacks & Pingbacks

  1. decltype and declval | musingstudio

Leave a Reply

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

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

Google photo

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

Twitter picture

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

Facebook photo

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

Connecting to %s

%d bloggers like this: