Create pseudo-method pointers

suggest change

This is an advanced example.

You can use variant for light weight type erasure.

template<class F>
struct pseudo_method {
  F f;
  // enable C++17 class type deduction:
  pseudo_method( F&& fin ):f(std::move(fin)) {}

  // Koenig lookup operator->*, as this is a pseudo-method it is appropriate:
  template<class Variant> // maybe add SFINAE test that LHS is actually a variant.
  friend decltype(auto) operator->*( Variant&& var, pseudo_method const& method ) {
    // var->*method returns a lambda that perfect forwards a function call,
    // behaving like a method pointer basically:
    return [&](auto&&...args)->decltype(auto) {
      // use visit to get the type of the variant:
      return std::visit(
        [&](auto&& self)->decltype(auto) {
          // decltype(x)(x) is perfect forwarding in a lambda:
          return method.f( decltype(self)(self), decltype(args)(args)... );
        },
        std::forward<Var>(var)
      );
    };
  }
};

this creates a type that overloads operator->* with a Variant on the left hand side.

// C++17 class type deduction to find template argument of `print` here.
// a pseudo-method lambda should take `self` as its first argument, then
// the rest of the arguments afterwards, and invoke the action:
pseudo_method print = [](auto&& self, auto&&...args)->decltype(auto) {
  return decltype(self)(self).print( decltype(args)(args)... );
};

Now if we have 2 types each with a print method:

struct A {
  void print( std::ostream& os ) const {
    os << "A";
  }
};
struct B {
  void print( std::ostream& os ) const {
    os << "B";
  }
};

note that they are unrelated types. We can:

std::variant<A,B> var = A{};

(var->*print)(std::cout);

and it will dispatch the call directly to A::print(std::cout) for us. If we instead initialized the var with B{}, it would dispatch to B::print(std::cout).

If we created a new type C:

struct C {};

then:

std::variant<A,B,C> var = A{};
(var->*print)(std::cout);

will fail to compile, because there is no C.print(std::cout) method.

Extending the above would permit free function prints to be detected and used, possibly with use of if constexpr within the print pseudo-method.

live example currently using boost::variant in place of std::variant.

Feedback about page:

Feedback:
Optional: your email if you want me to get back to you:


std::variant:
* Create pseudo-method pointers

Table Of Contents
8 Arrays
11 Loops
30 std::variant
39 Streams
51 Unions
56 Lambdas
60 SFINAE
62 RAII
67 Sorting
84 RTTI
87 Scopes
104 Profiling
107 Recursion
117 Iteration
125 Alignment
134 Semaphore
136 Debugging
139 Mutexes
142 decltype