建立偽方法指標

這是一個高階示例。

你可以使用變體進行輕量級擦除。

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)
      );
    };
  }
};

這會建立一個型別,在左側使用 Variant 過載 operator->*

// 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)... );
};

現在,如果我們有兩種型別,每種型別都有 print 方法:

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

請注意它們是不相關的型別。我們可以:

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

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

它將直接向我們傳送呼叫給 A::print(std::cout)。如果我們用 B{} 初始化 var,它將傳送到 B::print(std::cout)

如果我們建立了一個新型別 C:

struct C {};

然後:

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

將無法編譯,因為沒有 C.print(std::cout) 方法。

擴充套件上述內容將允許檢測和使用自由函式 prints,可能在 print 偽方法中使用 if constexpr

活生生的例子 ,當前使用的地方 std::variantboost::variant