我正在为我的一个项目编写一个简单的行为模型引擎。我现在正试图制作一个特定的函数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::Success
或State::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?
答案 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(); };
}