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"
}
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
^
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?
usingdeclaration to bring all of thoseoperator()'s into your own overload set. Thus allowing the C++ compiler to do the work of overload resolution for you. Once you can no longer use that trick, you're now stuck with manually implementing overload resolution. That will be... decidedly non-trivial. Good luck.overloadcan have a singleoperator()template, the you need to select which one of theTs...matches. You can take inspiration from the implementation ofstd::variantconstructor, which basically needs to solve the same problem.Boost.Variantimplements it here.