问题
I have this static_loop
construct that is used for type dispatching over loop unrolling.
template <std::size_t n, typename F> void static_loop(F&& f) {
static_assert(n <= 8 && "static loop size should <= 8");
if constexpr (n >= 8)
f(std::integral_constant<size_t, n - 8>());
if constexpr (n >= 7)
f(std::integral_constant<size_t, n - 7>());
if constexpr (n >= 6)
f(std::integral_constant<size_t, n - 6>());
if constexpr (n >= 5)
f(std::integral_constant<size_t, n - 5>());
if constexpr (n >= 4)
f(std::integral_constant<size_t, n - 4>());
if constexpr (n >= 3)
f(std::integral_constant<size_t, n - 3>());
if constexpr (n >= 2)
f(std::integral_constant<size_t, n - 2>());
if constexpr (n >= 1)
f(std::integral_constant<size_t, n - 1>());
}
template <typename T> constexpr size_t tupleSize(T) { return tuple_size_v<T>; }
struct A {
int a;
int b;
void run() {
auto ab = std::make_tuple(std::ref(a), std::ref(b));
static_loop<2>([&](auto i) {
std::get<i>(ab) = i;
static_loop<2>([&](auto j) { std::get<i * j>(ab) = i; });
// static_loop<2>([&, i = std::integral_constant<size_t, i>()](auto j) { std::get<i * j>(ab) = i; });
});
std::cout << a << " " << b << std::endl;
}
};
However it doesn't compile when doing nested loops. I'd assume i
and j
are both constexpr
thus i * j
is valid in std::get<>
, however, compiler seems not allowing this. Is it possible to capture i
as constexpr in the inner lambda?
Full example is at godbolt along with the error messages.
回答1:
static_loop<2>([&](auto i) {
std::get<i>(ab) = i;
static_loop<2>([&](auto j) { std::get<i * j>(ab) }
}
The IDE correctly underlines the error for you. i * j
is a multiplication of two variables, it is not a compile-time constant.
You can nest loops if you switch to template parameters rather than function arguments.
回答2:
This somehow works. Not sure if it violates any standard rules.
template <std::size_t n, typename F> void static_loop(F&& f) {
static_assert(n <= 8 && "static loop size should <= 8");
if constexpr (n >= 8)
f(std::integral_constant<size_t, n - 8>());
if constexpr (n >= 7)
f(std::integral_constant<size_t, n - 7>());
if constexpr (n >= 6)
f(std::integral_constant<size_t, n - 6>());
if constexpr (n >= 5)
f(std::integral_constant<size_t, n - 5>());
if constexpr (n >= 4)
f(std::integral_constant<size_t, n - 4>());
if constexpr (n >= 3)
f(std::integral_constant<size_t, n - 3>());
if constexpr (n >= 2)
f(std::integral_constant<size_t, n - 2>());
if constexpr (n >= 1)
f(std::integral_constant<size_t, n - 1>());
}
struct A {
int a;
int b;
void run() {
auto ab = std::make_tuple(std::ref(a), std::ref(b));
static_loop<2>([&](auto i) {
std::get<i>(ab) = i;
static_loop<2>([&](auto j) { auto ii = decltype(i)(); std::get<ii * j>(ab) = ii; });
});
std::cout << a << " " << b << std::endl;
}
};
The captured value might not be constexpr but its type is somehow retained.
来源:https://stackoverflow.com/questions/53978389/nested-static-loop-fails-to-work-due-to-constexpr-uncapturable