使用std :: variant命名静态调度

aer*_*sis 13 c++ c++17

我需要填写一些模板魔术来使以下代码片段起作用.

问题是我希望能够为std::variant接受两个参数的命名静态方法定义一个访问者类.如何填写Applicator::apply()调度工作?

struct EventA {};

struct EventB {};

struct EventC {};

using Event = std::variant<EventA, EventB, EventC>;

struct Visitor {
  enum class LastEvent { None, A, B, C };

  struct State {
    LastEvent last_event = LastEvent::None;
  };

  static State apply(State s, EventA e) { return State{LastEvent::A}; }

  static State apply(State s, EventB e) { return State{LastEvent::B}; }
};

template <typename Visitor> struct Applicator {

  static State apply(State s, Event e) {

    /*** Start of pseudo code ***/
    if (Visitor can apply) {
      return Visitor::apply(s, e);
    }
    /*** End of pseudo code ***/

    // Else, don't update state state
    return s;
  }
};

int main() {
  // Handled by visitor
  State s1 = Applicator<Visitor>::apply(State{}, EventA{});
  assert(s1.last_event == Visitor::LastEvent::A);

  // Handled by visitor
  State s2 = Applicator<Visitor>::apply(State{}, EventB{});
  assert(s2.last_event == Visitor::LastEvent::B);

  // NOT handled by visitor
  State s3 = Applicator<Visitor>::apply(State{}, EventC{});
  assert(s3.last_event == Visitor::LastEvent::None);
}
Run Code Online (Sandbox Code Playgroud)

Max*_*kin 7

另一种方案:

using State = Visitor::State;

template<class Visitor>
struct VisitorProxy {
    State s;

    template<class E>
    auto operator()(E const& e) -> decltype(Visitor::apply(s, e)) {
        return Visitor::apply(s, e);
    }

    template<class E>
    State operator()(E const&) const {
        return s;
    }
};

template <typename Visitor> struct Applicator {
    static State apply(State s, Event e) {
        VisitorProxy<Visitor> p{s};
        return std::visit(p, e);
    }
};
Run Code Online (Sandbox Code Playgroud)

  • 优先考虑`const` ...现在这是一个我以前没见过的巧妙技巧.整齐! (2认同)

Que*_*tin 5

使用现在很常见的overloaded类模板伎俩(马克西姆的把戏基础上订购lambda表达式const他们的岬operator())来创建一个SFINAE能力的仿造型你lookig的逻辑:

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

// ...

template <typename Visitor> struct Applicator {
  static typename Visitor::State apply(typename Visitor::State s, Event e) {
    return std::visit(overloaded{
      [&s](auto e) mutable -> decltype(Visitor::apply(s, e)) { return Visitor::apply(s, e); },
      [&s](auto) { return s; }
    }, e);
  }
};
Run Code Online (Sandbox Code Playgroud)

请注意,这个ICE所有版本的Clang我都在Wandbox上测试过,但我还没有找到解决方法.完美转发留给读者作为练习:)