The idea is to be able to create an object with several operator() taken from lambda expressions in order to overload it. The idea works fine when we have a definite number of types (callables) but it explotes when we extend it to unlimited number of types. There must be some error in the code for the variadic template case.
First I will show you the one that works:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
template<typename F1, typename F2>
struct overload_s : public F1, public F2
{
overload_s(F1&& f1, F2&& f2) : F1(std::forward<F1>(f1)), F2(std::forward<F2>(f2)) {}
overload_s(const F1& f1, F2&& f2) : F1(f1), F2(std::forward<F2>(f2)) {}
using F1::operator();
using F2::operator();
};
template<typename F1, typename F2>
auto over(F1&& f1, F2&& f2 )
{
return overload_s<F1, F2>(std::forward<F1>(f1), std::forward<F2>(f2));
}
This works with this code:
1 2 3 4 5 6 7 8 9 10 11 12 13
void useO()
{
int i = 5;
double d = 7.3;
auto l = over(
([](int* i) {std::cout << "i=" << *i << std::endl; }),
([](double* d) {std::cout << "d=" << *d << std::endl; })
);
l(&i);
l(&d);
}
template <typename... Fs>
class overload_set: public Fs...
{
using Fs::operator()...;
};
template <typename... Fs>
overload_set(Fs...) -> overload_set<Fs...>;
Generally, pass function objects by value. This way a user can opt-in to reference semantics by using std::reference_wrapper.
The standard library mostly follows this guideline. For example, in addition to everything in <algorithm>, std::function takes callable objects by value too.
This snippet doesn't work for function objects that are final.
@mboziz your code does not compile for me in Visual Studio 19 v16.9.1. I had to add a constructor like so:
1 2 3 4 5 6 7
template<typename...Fs>
class overload_set17 : public Fs...
{
public:
overload_set17(Fs&&...fs) : Fs(std::forward<Fs>(fs))... {}
using Fs::operator()...;
};