Consider the following code:
#include <iostream>
#include <utility>
#include <array>
#include <functional>
#include <ctime>
template <unsigned N> void foo() { std::cout << N << "(" << ") "; }
template<> void foo<2>() { std::cout << "TWO (" << ") "; }
struct Foo {
template <unsigned N> void operator()(std::integral_constant<unsigned,N>) { foo<N>(); }
};
template <std::size_t Offset, std::size_t... Idx, typename F>
void visit(F f, std::index_sequence<Idx...>, std::size_t n) {
static std::array<std::function<void()>, sizeof...(Idx)> funcs {{
[&f](){f(std::integral_constant<unsigned,Idx+Offset>{});}...
}};
funcs[n - Offset]();
};
template <std::size_t Start, std::size_t End, typename F>
void visit(F f, std::size_t n) {
visit<Start>(f, std::make_index_sequence<End-Start>{}, n);
};
int main() {
auto t = time(nullptr);
for(int i = 0; i < 10; i++) {
visit<1, 10>(Foo{}, (t+i) % 10);
}
}
This is valid C++14 (actually, also valid C++11 if you write your own std::index_sequence
). But - it doesn't compile with g++ 6.x and 7.x; only g++ 8.x compiles it properly (see this happening on GodBolt).
For organizational reasons, I can require use g++ version up to 7.2. Is there a way I could alter the code while keeping the semantics, to make g++ 7.x compile it?
GCC's bug is that it can't pack expand lambdas. So don't pack expand lambdas.
template<class F, std::size_t Idx>
void caller(F& f) { f(std:::integral_constant<unsigned, Idx>()); }
template <std::size_t Offset, std::size_t... Idx, typename F>
void visit(F f, std::index_sequence<Idx...>, std::size_t n) {
using ptr_type = void (*)(F&);
static constexpr ptr_type funcs[] = {&caller<F, Idx+Offset>...};
funcs[n-Offset](f);
}