Tomilov Anatoliy
Tomilov Anatoliy

Reputation: 16731

How to make the boost::apply_visitor a friend-function of the class-visitor?

How to make the boost::apply_visitor (either of two variants) a friend-function of class-visitor?

I have tried the following: friend result_type boost::apply_visitor<>(decltype(*this) &, instruction_type const &);, but this does not work. *this derived from boost::static_visitor (or have using result_type = ...; typedef) and instruction type is the boost::variant of some specific types. *this have all required operator ()-s in private section.

What is the right form of such declaration?

Upvotes: 2

Views: 559

Answers (1)

sehe
sehe

Reputation: 393259

If you insist, you could wrap your actual visitor in a visitor that exposes the required interface, and declare that as a friend of your visitor-impl (that now combines the impl and visitor concepts).

(The "good" (cough) thing here is that there is not need for the impl to be polymorphic or dynamically allocated.)

Here's a stratight-forward proof of concept:

#include <boost/variant.hpp>

namespace detail
{
    template <typename R, typename Wrapped>
        struct WrapVisitor : boost::static_visitor<R>
    {
        template <typename... T> R operator()(T&&... args) const { return _wrapped(std::forward<T>(args)...); }

        WrapVisitor(Wrapped&& wrapped) : _wrapped(std::move(wrapped)) {}
     private:
        Wrapped _wrapped;
    };
}

template <typename R, typename Wrapped>
detail::WrapVisitor<R, Wrapped> wrap(Wrapped&& wrapped) {
    return { std::forward<Wrapped>(wrapped) };
}

And here's how you'd use it with a demo visitor that hides all implementation details:

class PrivateVisistorImp : protected boost::static_visitor<double>
{
    double operator()(int i)    const { return -i;   }
    double operator()(double d) const { return d*10; }

    friend detail::WrapVisitor<double, PrivateVisistorImp>;
};

Of course, it has the cost of needing to instantiate the wrapped visitor at the call site:

int main()
{
    using Var = boost::variant<int, double>;

    Var a = 3.14, b = 42;
    auto w = wrap<double>(PrivateVisistorImp());
    std::cout << boost::apply_visitor(w, a) << "\n";
    std::cout << boost::apply_visitor(w, b) << "\n";
}

See it all Live on Coliru

Upvotes: 3

Related Questions