如何在 C++ 编译时应用 if

How to apply an if at compile time in C++

我正在尝试编写一个通用的 static_for 实现,它可以接受边界、增量函数和比较函数 运行 循环。我一直在使用这个结构和递增 1 的简单循环。在这种情况下,很容易通过简单地专注于 IDX & END 相等来停止循环展开。

但是当增量可以是任意整数时,不能保证IDX & END总是相等的。 if 条件仅在 运行 时评估。在下面的代码片段中,我试图专注于停止递归的 std::false_type 。 integral_constant 是通过计算 std::less 泛函构建的(用户可以用任何其他计算代替)。不幸的是,此 comparator 函数也仅在 运行 时评估,因此编译器失败。有人可以建议如何让它工作吗?

注意:使用 C++11。

template <int idx, int end, typename eval, int count, typename comparator>
struct static_for_loop {
  template <typename Lambda, typename... Args>
  void operator()(const Lambda& function, Args... args) const {
    if (comparator()(idx, end)) {
      std::integral_constant<int, idx> i;

      function(i, args...);

      constexpr bool lesser = comparator()(idx + count, end);
      static_for_loop<idx + count, end, std::integral_constant<bool, lesser>, count,
                      comparator>()(function, args...);
    }
  }
};

template <int idx, int end, int count, typename comparator>
struct static_for_loop<idx, end, std::false_type, count, comparator> {
  template <typename Lambda, typename... Args>
  void operator()(const Lambda& function, Args... args) const {}
};

template <int idx, int end, int count = 1, typename comparator = std::less<int>>
struct static_for {
  template <typename Lambda, typename... Args>
  void operator()(const Lambda& function, Args... args) const {
    static_for_loop<idx, end, std::true_type, count, comparator>()(function, args...);
  }
};

我发现将所有内容包装在一个对象中更容易:

template <int S, int E, int step>
struct iter {
    auto next() { return iter<std::min(E, S+step), E, step>{}; }
};

然后对于完成的情况和未完成的情况,你只需要一个重载:

template <int S, int E, int step, class F, class... Args>
void for_loop(iter<S, E, step> i, F func, Args... args) {
    func(S, args...);

    for_loop(i.next(), func, args...);
}

template <int E, int step, class F, class... Args>
void for_loop(iter<E, E, step>, F, Args... ) {
}

例如:

// prints 0 4 8
for_loop(iter<0, 10, 4>{}, [](int i){std::cout << i << ' ';});   

或者,可以使用 enable_if 来区分大小写以避免需要 min:

template <int S, int E, int step, class F, class... Args>
std::enable_if_t<(S<E)> for_loop(iter<S, E, step>, F func, Args... args)
{
    func(S, args...);
    for_loop(iter<S+step, E, step>{}, func, args...);
}

template <int S, int E, int step, class F, class... Args>
std::enable_if_t<!(S<E)> for_loop(iter<S, E, step>, F , Args... )
{
}

您喜欢的 YMMV。

您可以使用sfinae解决问题:

template <int idx, int end, typename eval, int count, typename Comparator>
struct static_for_loop {
    template <typename Lambda, typename... Args>
    auto operator()(Lambda&& function, Args&&... args) const
    -> std::enable_if_t<Comparator{}(idx, end)> {
        std::integral_constant<int, idx> i;

        std::forward<Lambda>(function)(i, std::forward<Args>(args)...);

        constexpr bool lesser = comparator{}(idx + count, end);

        static_for_loop<
            idx + count,
            END,
            std::integral_constant<bool, lesser>,
            count,
            Comparator
        >()(std::forward<Lambda>(function), std::forward<Args>(args)...);
    }

    // do nothing when false
    template <typename Lambda, typename... Args>
    auto operator()(Lambda&& function, Args&&... args) const
    -> std::enable_if_t<!Comparator{}(idx, end)> {

    }
};

std::enable_if 将 select 与 sfinae 的正确功能。如果.

它将充当编译时间

我也使用了完美转发,因为您的代码并非在所有情况下都有效,例如传递不可复制或可变的 lambda。现在会了。

如果你没有c++14,你可以写成typename std::enable_if<...>::type

尽量少用全大写的名字,会影响听力。

是不是你没有指定comparator的问题?只需指定您的 API,如果循环应继续 IDX,则 comparator<IDX>::typestd::true_type,并在 false_type 时停止。然后,您的简单循环案例使用 template<int IDX> using Comp = std::integral_constant<bool, (IDX < 5)>`。