constexprify行为测序功能

时间:2017-04-28 07:26:34

标签: c++ artificial-intelligence c++17

我正在为我的一个项目编写一个简单的行为模型引擎。我现在正试图制作一个特定的函数constexpr。

问题是在底部,静止是背景信息

框架如何运作的简短说明

行为节点可以返回以下三种状态之一:

enum class State { Fail, Success, Running }; 

默认叶节点总是返回以下三种状态之一:

constexpr inline auto success() { return []{ return State::Success; }; }                                 
constexpr inline auto fail()    { return []{ return State::Fail;    }; }                                 
constexpr inline auto running() { return []{ return State::Running; }; }

可以执行不同的操作,例如否定:

constexpr inline auto operator~(auto rule) {
  return [rule]{                                                                                         
    const auto result = rule();                                                                          
    return result == State::Fail ? State::Success :                                                      
           result == State::Success ? State::Fail :                                                      
           State::Running;                                                                               
  };                                                                                                     
}

......和其他逻辑操作:

constexpr inline auto operator&&(auto left, auto right) {
  return [left, right]{
    const auto lresult = left();
    const auto rresult = right();
    return (lresult == State::Fail || rresult == State::Fail) ? State::Fail :
           (lresult == State::Success && rresult == State::Success) ? State::Success :
           State::Running;
  };
}

最后有评价函数,非常简单:

inline State execute(auto rule) {
  return rule();
}

实施例

CHECK( State::Success == execute(success() && success()) );
CHECK( State::Fail    == execute(success() && fail()) );

实施例

在编写此示例时,我无法访问C ++ 17编译器,因此无法实际编译和测试它。

这里我们使用可能在编译时评估的混合规则,以及一些用于运行时的规则。一个家伙走到一扇锁着的门,并试图打开它,如果他有一把钥匙在编译时决定。

auto walking                 = false;
auto door_open               = false;
auto is_at_door              = false;
constexpr auto dude_has_key  = false;

constexpr auto unlock_door = []{return []{
    return dude_has_key ? State::Success : State::Fail;
};};

const auto walk_to_door = [&]{return []{
    if(walking) { // Stop at the door
        walking    = false;
        is_at_door = true;
        return State::Success;
    }
    if(!is_at_door) {
        walking = true;
        return State::Running;
    }
    return State::Fail; // Cannot walk through the door
};};

const auto open_door = [&]{return []{
    // We want to compile-time check if the door is locked
    // hence we never check for that condition here.
    if(!door_open) {
        door_open = true;
    }
    return State::Success
};};

const auto rules = sequence({walk_to_door, unlock_door && open_door});
CHECK( State::Running == execute(rules) ); // Walking to door
CHECK( State::Fail    == execute(rules) ); // Cannot unlock door

实施例

在编写此示例时,我无法访问C ++ 17编译器,因此无法实际编译和测试它。

struct MyThing {
    static constexpr bool PropertyA = true;
    static constexpr int  PowerLevel = 42;
};

struct YourThing {
    static constexpr bool PropertyA = false;
    static constexpr int  PowerLevel = 43;
};

constexpr auto has_property_a(auto thing) {
    return []{ return decltype(thing)::PropertyA ? State::Success :: State::Fail; };
}

constexpr auto has_minimum_power_level(auto thing, auto min_pl) {
    return []{ return decltype(thing)::PowerLevel > min_pl ? Satet::Success ::State::Fail; };
} 

template<typename ThingA, typename ThingB>
constexpr auto rule = sequence({
    has_property_a(ThingA{}), 
    has_minimum_power_level(ThingB{}, 9000)
});
execute(sequence({rule<MyThing,YourThing>, __some_runtime_rule});

当前问题

...是测序函数,应该通过以下测试

CHECK( State::Success       == execute(sequence({success(), success(), success()})) );
CHECK( State::Fail          == execute(sequence({success(), success(), fail()})) );
CHECK( State::Running       == execute(sequence({success(), success(), running()})) );
// last (fail) never evaluated due to 2nd being running
CHECK( State::Running       == execute(sequence({success(), running(), fail()})) ); 

换句话说,当序列中的所有节点返回State::Success时,它返回State::Success。如果它遇到State::Running,则会在State::SuccessState::Fail之前“等待”。 State::Fail使整个序列失败。

此函数的当前make-the-tests-pass-implementation看起来像

using Rule = std::function<State()>;
inline auto sequence(std::initializer_list<Rule> rules) {
  return [rules]{
    auto result = State::Success;
    for(auto next : rules) {
      const auto next_result = next();
      result = (result == State::Success && next_result == State::Success) ? State::Success :
               (result == State::Success && next_result == State::Running) ? State::Running :
               State::Fail;
      if(result == State::Fail || result == State::Running) {
        return result;
      }
    }
    return State::Success;
  };
}

现在我该如何制作这个constexpr?

1 个答案:

答案 0 :(得分:2)

如果您的序列只是要重复应用&amp;&amp;,那么您可以用折叠指定它

允许空sequence()(返回相当于success

template <typename ... Rules>
constexpr auto sequence(Rules ... rules)
{
    return [rules...](){ return State::Success && ... && rules(); };
}

或至少需要一个规则

template <typename First, typename ... Rules>
constexpr auto sequence(First first, Rules ... rules)
{
    return [first, rules...](){ return first() && ... && rules(); };
}