C++ 将可变参数模板参数扩展为语句

C++ expand variadic template arguments into a statement

我目前正在研究模板元编程。我正在尝试使用 tmp 制作一个有限状态机。我知道网络上有多种实现,但我想自己实现一个作为练习。

我有一个名为 Condition 的 class,它是两个状态之间转换条件的基础 class。一种实现是 AnyCondition class:

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...
    }

这有可能吗?

有一个很好的逗号技巧

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;
}

C++17 解决方案 - fold expression:

template <typename... Ts>
auto anyCondition(Ts... xs)
{
    return (xs || ...);
}

wandbox example


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;
}   

wandbox example

我在 CppCon 2015 上就这个片段发表了演讲:
CppCon 2015: Vittorio Romeo “for_each_argument explained and expanded"

我非常确定任何体面的编译器都会将递归优化为循环。但是,如果您正在寻找一些额外的方法来扩展单一类型的可变参数列表,您可以使用简单的 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;
}