如何在 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>::type
为 std::true_type
,并在 false_type
时停止。然后,您的简单循环案例使用 template<int IDX> using Comp = std::integral_constant<bool, (IDX < 5
)>`。
我正在尝试编写一个通用的 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>::type
为 std::true_type
,并在 false_type
时停止。然后,您的简单循环案例使用 template<int IDX> using Comp = std::integral_constant<bool, (IDX < 5
)>`。