Daniel McLaury
Daniel McLaury

Reputation: 4303

Is there a clean way to turn an overload set into a visitor suitable for use with std::visit?

Suppose I have an overload set, like so:

class C
{
  public: 

    static void f(const A &);
    static void f(const B &);
};

I'd like to do something like

std::variant<A, B> v;

// ...

std::visit(C::f, v);

but this doesn't compile. Is there some way of taking an overload set and regarding it as, or converting it to, a Visitor?

Upvotes: 3

Views: 363

Answers (3)

user14217014
user14217014

Reputation:

If you can make an instance of class C, you could overload the member operator() on class C to call the appropriate function based on the variant type:

#include <iostream>
#include <variant>

struct A {};
struct B {};

class C
{
    public:    
    template <typename T>
    void operator()(const T& t) { C::f(t); }

    static void f(const A &) { std::cout << "A\n"; }
    static void f(const B &) { std::cout << "B\n"; }
};

int main()
{
    std::variant<A, B> v_a = A{};
    std::variant<A, B> v_b = B{};
    C c;
    std::visit(c, v_a); // "A"
    std::visit(c, v_b); // "B"
    return 0;
}

Upvotes: 1

Justin
Justin

Reputation: 25387

If you already use Boost, Boost.HOF has a utility to wrap an overload set for you: BOOST_HOF_LIFT:

std::visit(BOOST_HOF_LIFT(C::f), v);

Demo

Upvotes: 2

Daniel McLaury
Daniel McLaury

Reputation: 4303

Actually, after playing around with this further I've realized that I can do

std::visit([](const auto & t) { C::f(t); }, v);

so I'll leave this here as a potential solution for anyone else with the same problem.

Upvotes: 5

Related Questions