我正在玩模板元编程。我正在尝试使用tmp创建一个有限状态机。我知道网上有几个实现,但我想自己实现一个练习。
我有一个名为Condition
的类,它是两个状态之间转换条件的基类。一个实现是AnyCondition
类:
template<class Input, Input comp, Input ... comps >
class AnyCondition: public Condition<Input>
{
public:
AnyCondition() {}
bool operator()(const Input& input) const override
{
return input == comp || AnyCondition<Input, comps...>()(input);
}
};
这里的事情是,编译器会递归地扩展它,由于input
参数导致在运行时进行大量的递归调用。如果扩展代码是如下语句,那应该更有效率。
bool operator()(const Input& input) const override
{
return input == comp1 || input == comp2 || input == comp3...
}
这有可能吗?
答案 0 :(得分:4)
C ++ 17解决方案 - fold expression:
template <typename... Ts>
auto anyCondition(Ts... xs)
{
return (xs || ...);
}
C ++ 11解决方案 - for_each_argument
:
template <typename TF, typename... Ts>
void for_each_argument(TF&& f, Ts&&... xs)
{
(void)(int[]){(f(std::forward<Ts>(xs)), 0)...};
}
template <typename... Ts>
auto anyCondition(Ts... xs)
{
bool acc = false;
for_each_argument([&acc](bool x){ acc = acc || x; }, xs...);
return acc;
}
我在CppCon 2015上谈到了这个片段:
CppCon 2015: Vittorio Romeo “for_each_argument
explained and expanded"
答案 1 :(得分:2)
我非常确定任何体面的编译器都会优化递归循环。但是,如果您正在寻找一些额外的方法来扩展单个类型的可变参数列表,您可以使用简单的std::initializer_list
技巧:
constexpr auto list = {comp, comps...};
或者,在您的情况下:
inline bool operator()(const Input &input) const override {
bool res = false;
for (auto val : {comp, comps...})
res |= val == input;
return res;
}
答案 2 :(得分:1)
有一个很好的旧逗号技巧
bool operator()(const Input& input) const override
{
bool ret { input == comp };
int unusedA [] { ( ret |= (input == comps), 0 ) ... };
(void)unusedA; // to avoid the unused warning
return ret;
}