More C++ Idioms/Return Type Resolver
Return Type Resolver
edit
Intent
editDeduce the type of the variable being initialized or assigned to.
Also Known As
editMotivation
editThe 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
editReturn 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
editThe 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.