More C++ Idioms/Return Type Resolver

Return Type Resolver

edit

Intent

edit

Deduce the type of the variable being initialized or assigned to.

Also Known As

edit

Motivation

edit

The type of the variable being initialized can be a useful information to have in certain contexts. Consider, for instance, we want to initialize STL containers with random numbers. However, we don't know the exact type of the container expected by the user. It could be std::list, std::vector or something custom that behaves like STL container. A straight-forward approach to write and use such a function would be as follows.

template <class Container>
Container getRandomN(size_t n) 
{
  Container c;
  for(size_t i = 0;i < n; ++i)
    c.insert(c.end(), rand());
  return c;
}

int main (void)
{
   std::list<int> l = getRandomN<std::list<int> > (10);
   std::vector<long> v = getRandomN<std::vector<long> > (100);
}

Note that the type of the container must be passed to the function because that is the desired return type of the function. Clearly, the type must be repeated at-least twice. Return type resolver idiom can be used to address this issue.

Solution and Sample Code

edit

Return type resolver idiom makes use of a proxy class and templatized conversion operator functions in the class. getRandomN function above can be implemented with a class and a member conversion function as follows.

class getRandomN 
{
  size_t count;

public:
  getRandomN(int n = 1) : count(n) {}

  template <class Container>
  operator Container () {
    Container c;
    for(size_t i = 0;i < count; ++i)
      c.insert(c.end(), rand()); // push_back is not supported by all standard containers.
    return c;
  }
};

int main()
{
  std::set<int> random_s = getRandomN(10);
  std::vector<int> random_v = getRandomN(10);
  std::list<int> random_l = getRandomN(10);
}

getRandomN class has a constructor and a templatized conversion operator function. For initialization, a temporary object of getRandomN class is created and assigned to the desired container class. C++ compiler attempts to convert the temporary object into the container class object. The only way to do that is via the conversion operator. The conversion operator is instantiated with the type of the container that is being populated. Due to automatic resolution of the return type, the user does not have to spell it out again. Note that insert member function has been used instead of push_back because std::set does not support push_back.

Known Uses

edit

The nullptr idiom makes use of the return type resolver idiom to automatically deduce a null pointer of the correct type depending upon the pointer variable it is assigning to.

edit

References

edit