在运行时询问变体中的替代是否满足某个概念



我有以下代码,我尝试在其中检测变体中的替代概念(在本例中为成员函数)。它很冗长,相对丑陋。有没有更好的方法可以做到这一点?请注意,我不想使用继承,也不想使用静态多态性(假设在编译时不知道使用什么引擎)。

简单来说,我正在寻找if constexpr(仅在编译时检查概念)和std::holds_alternative(只能检查特定类型是否在variant中,而不是满足该概念的任何类型是否在variant中)的运行时组合。

#include <iostream>
#include <variant>

struct simple_engine1{
};
struct simple_engine2{
};
struct complex_engine1{
    void reduce_thrust(int perc){
        std::cout<<"reducing thrust " << perc << "% " << std::endl;
    }
};
struct complex_engine2{
    void reduce_thrust(int perc){
        std::cout<<"reducing thrust " << perc << "% " << std::endl;
    }
};
template< class, class = std::void_t<> >
struct has_reduce_thrust : std::false_type { };
template< class T >
struct has_reduce_thrust<T,
           std::void_t<decltype( std::declval<T>().reduce_thrust(42) )>
       > : std::true_type { };
static_assert(!has_reduce_thrust<simple_engine1>::value);
static_assert(!has_reduce_thrust<simple_engine1>::value);
static_assert(has_reduce_thrust<complex_engine1>::value);
struct visitor{
  template<typename T>
  void operator()(T& t){
      dispatch(t, has_reduce_thrust<T>{});
  }
  template<typename T>
  void dispatch(T& t, std::true_type /*has_reduce_thrust*/){
      t.reduce_thrust(perc);
      reduced_thrust=true;
  }
  template<typename T>
  void dispatch(T& , std::false_type){
      reduced_thrust=false;
  }
  int perc = 0;
  bool reduced_thrust = false;  
};
// tries to reduce speed by reducing thrust if engine supports it, if not
// it fires reverse engines(more expensive wrt fuel usage)
void reduce_speed(std::variant<simple_engine1, simple_engine2, complex_engine1, complex_engine2>* var_engine){
    visitor v;
    v.perc = 47;
    std::visit(v, *var_engine);
    if (v.reduced_thrust) {
        std::cout << "reduced thrustn"; 
    } else {
        std::cout << "activating reverse enginesn";
    }
}
int main() {
    std::variant<simple_engine1, simple_engine2, complex_engine1, complex_engine2> var_engine{simple_engine1{}};
    reduce_speed(&var_engine);
    var_engine = complex_engine2{};
    reduce_speed(&var_engine);
    var_engine = simple_engine2{};
    reduce_speed(&var_engine);
    var_engine = complex_engine2{};
    reduce_speed(&var_engine);
} 

您可以使用if constexpr大大简化访问者:

struct visitor{
  template<typename T>
  void operator()(T& t) {
    if constexpr (has_reduce_thrust<T>::value) {
      t.reduce_thrust(perc);
      reduced_thrust = true;
    }
    else {
      reduced_thrust = false;
    }
  }
  int perc = 0;
  bool reduced_thrust = false;  
};

然后,您可以通过接受if constexpr任一分支的任何谓词和两个函数来进一步抽象:

template <template <class, class... /*SFINAE friendly*/> class TypePred,
          class MatchedFunc, class UnmatchedFunc>
class predicated_visitor {
 public:
  predicated_visitor(MatchedFunc matchedFunc, UnmatchedFunc unmatchedFunc)
      : _matchedFunc(matchedFunc), _unmatchedFunc(unmatchedFunc) {}
  template <typename T>
  void operator()(T& t) {
    if constexpr (TypePred<T>::value)
      _matchedFunc(t);
    else
      _unmatchedFunc(t);
  }
 private:
  MatchedFunc _matchedFunc;
  UnmatchedFunc _unmatchedFunc;
};
template <template <class, class... /*SFINAE friendly*/> class TypePred,
          class F1, class F2>
auto makePredicatedVisitor(F1 f1, F2 f2) {
  return predicated_visitor<TypePred, F1, F2>(f1, f2);
}

我觉得生成的代码非常好:

void reduce_speed(std::variant<simple_engine1, simple_engine2, complex_engine1,
                               complex_engine2>* var_engine) {
  int perc = 47;
  bool reducedThrust = false;
  auto reduceableThrustAction = [perc, &reducedThrust](auto& t) {
    t.reduce_thrust(perc);
    reducedThrust = true;
  };
  auto alternativeAction = [](auto& t) {
  };  // Could explicitly set reduceThrust to false for clarity.
  auto thrust_visitor = makePredicatedVisitor<has_reduce_thrust>(
      reduceableThrustAction, alternativeAction);
  std::visit(thrust_visitor, *var_engine);
  if (reducedThrust) {
    std::cout << "reduced thrustn";
  } else {
    std::cout << "activating reverse enginesn";
  }
}

演示

此示例编译为与您的程序集代码基本相同的程序集代码,但可以以您喜欢的任何方式重用。

对于大小写不一致,我深表歉意...

相关内容

  • 没有找到相关文章

最新更新