Home » C++ » How can Boost be used to achieve C++14-style auto return types?

How can Boost be used to achieve C++14-style auto return types?

Posted by: admin November 29, 2017 Leave a comment

Questions:

Suppose I have a function that adds two values together. If I know nothing about the types then I basically have to write my function twice; once in the actual return value and again as the return type specifier:

template <typename A, typename B>
auto Add(const A& a, const B& b) ->std::decay<decltype(a + b)>::type
{
  return a + b;
}

While this works, it is undesirable because it is difficult to read and difficult to maintain.

In C++14 this won’t be an issue, because we can drop the return type specifier (I am not sure it’ll do the decay though…). For now, I’m stuck with C++11.

It has been my experience that whenever I am seeking a feature in C++ that hasn’t yet made its way into the standard, but for which there is an obvious need, the Boost library usually has a solution. I have searched through the documentation, but I haven’t found anything that might help me. The BOOST_AUTO_RETURN and BOOST_TYPEOF_TPL features seem more aimed at providing C++11 functionality to C++03 users.

Basically what I’m after is something that performs the following functionality:

template <typename A, typename B>
auto Add(const A& a, const B& b)
{
  return a + b; // Deduce return type from this, like C++14 would
}

Is there some functionality in the Boost library that I’m unaware of (or a nifty trick in C++11) that might allow me to forego the explicit -> decltype(...) after every auto return type? How would this be implemented?

Answers:

The only possible deduced function return type in C++11 is the return type of a lambda. C++11 restricts the use of lambdas, though. This works:

auto add = [](int a, int b) { return a + b; };

This is valid, and defines add as a lambda that defines an operator() member function that returns int. Since the lambda doesn’t capture anything, you can even write

auto add = +[](int a, int b) { return a + b; };

to make add a regular pointer-to-function: it gets type int(*)(int, int).

However, C++11 doesn’t allow parameter types to be specified as auto, nor to let add be defined as a template variable, so you cannot use this to generically deduce a return type. An attempt to wrap it up in a template class fails:

template <typename A, typename B>
struct S { static auto add = [](A a, B b) { return a + b; }; }; // invalid

It is invalid to initialise add in-class here, and you cannot use auto unless the member is initialised in-class. Besides, even if it did work, it wouldn’t allow deduction of A or B, which seems to be more what you’re after.

Given those limitations, I don’t see any alternative but to repeat the expression. You could hide the repetition in a trivial macro, though.

#define AUTO_RETURN(func, ...) auto func -> decltype(__VA_ARGS__) { return __VA_ARGS__; }

template <typename A, typename B>
AUTO_RETURN(add(A a, B b), a + b)

Or the variant pointed out by Marc Glisse,

#define RETURNS(...) noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { return __VA_ARGS__; }

template <typename A, typename B>
auto add(A a, B b) RETURNS(a + b)

which looks a bit cleaner.

There might be something like this in Boost already, I don’t know. Regardless, given the triviality, Boost seems overkill here.

Questions:
Answers:

There is a library Pythy that tries emulate this syntax. However, it will only work on clang. It doesn’t work on gcc due to these bugs here and here. They may be fixed for gcc 4.9, but if you are using gcc 4.9 you can use auto return types, anyways.