How can Boost be used to achieve C++14-style auto return types?
C++C++11BoostC++ Problem Overview
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?
C++ Solutions
Solution 1 - C++
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.