In C++17, it is trivial to implement an overload(fs...)
function that, given any number of arguments fs...
satisfying FunctionObject
, returns a new function object that behaves like an overload of fs...
. Example:
template <typename... Ts>
struct overloader : Ts...
{
template <typename... TArgs>
overloader(TArgs&&... xs) : Ts{forward<TArgs>(xs)}...
{
}
using Ts::operator()...;
};
template <typename... Ts>
auto overload(Ts&&... xs)
{
return overloader<decay_t<Ts>...>{forward<Ts>(xs)...};
}
int main()
{
auto o = overload([](char){ cout << "CHAR"; },
[](int) { cout << "INT"; });
o('a'); // prints "CHAR"
o(0); // prints "INT"
}
live example on wandbox
Since the above overloader
inherits from Ts...
, it needs to either copy or move the function objects in order to work. I want something that provides the same overloading behavior, but only references to the passed function objects.
Let's call that hypothetical function ref_overload(fs...)
. My attempt was using std::reference_wrapper
and std::ref
as follows:
template <typename... Ts>
auto ref_overload(Ts&... xs)
{
return overloader<reference_wrapper<Ts>...>{ref(xs)...};
}
Seems simple enough, right?
int main()
{
auto l0 = [](char){ cout << "CHAR"; };
auto l1 = [](int) { cout << "INT"; };
auto o = ref_overload(l0, l1);
o('a'); // BOOM
o(0);
}
error: call of '(overloader<...>) (char)' is ambiguous
o('a'); // BOOM
^
live example on wandbox
The reason it doesn't work is simple: std::reference_wrapper::operator()
is a variadic function template, which does not play nicely with overloading.
In order to use the using Ts::operator()...
syntax, I need Ts...
to satisfy FunctionObject
. If I try to make my own FunctionObject
wrapper, I encounter the same issue:
template <typename TF>
struct function_ref
{
TF& _f;
decltype(auto) operator()(/* ??? */);
};
Since there's no way of expressing "compiler, please fill the ???
with the exact same arguments as TF::operator()
", I need to use a variadic function template, solving nothing.
I also cannot use something like boost::function_traits
because one of the functions passed to overload(...)
may be a function template or an overloaded function object itself!
Therefore my question is: is there a way of implementing a ref_overload(fs...)
function that, given any number of fs...
function objects, returns a new function object that behaves like an overload of fs...
, but refers to fs...
instead of copying/moving them?
question from:
https://stackoverflow.com/questions/42987144/overloading-multiple-function-objects-by-reference