0

考虑以下代码:

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

这是有效的 C++14(实际上,如果您编写自己的 C++11 也是有效的std::index_sequence)。但是 - 它不能用 g++ 6.x 和 7.x 编译;只有 g++ 8.x 可以正确编译它(参见GodBolt 上发生的这种情况)。

出于组织原因,我可以要求使用最高 7.2 的 g++ 版本。有没有办法在保持语义的同时改变代码,让 g++ 7.x 编译它?

4

2 回答 2

2

GCC 的错误是它不能打包扩展 lambda。所以不要打包扩展 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);
}
于 2018-11-07T19:07:41.487 回答
0

我用一块石头击中了两只鸟,并将这种访问机制扩展到采用任意数量参数的函数。并且 whaddaya 知道 - 这意味着将 lambda 移动到辅助函数中,以避免不同的参数包相互干扰。正如@TC 所建议的那样 - 这就是 GCC 遇到的麻烦,因此可以避免这个问题。

template <std::size_t N, typename F, typename... Ts>
std::function<void(Ts...)> make_visitor(F f) {
    return 
        [&f](Ts... args) {
            f(std::integral_constant<std::size_t,N>{}, std::forward<Ts>(args)...);
        };
}

template <std::size_t Offset, std::size_t... Idx, typename F, typename... Ts>
void visit(F f, std::index_sequence<Idx...>, std::size_t n, Ts... args) {
    static std::array<std::function<void(Ts...)>, sizeof...(Idx)> funcs {{
        make_visitor<Idx+Offset, F, Ts...>(f)...
    }};
    funcs[n-Offset](std::forward<Ts>(args)...);
};

template <std::size_t Start, std::size_t End, typename F, typename... Ts>
void visit(F f, std::size_t n, Ts... args) {
    visit<Start>(f, std::make_index_sequence<End-Start>{}, n, std::forward<Ts>(args)...);
};
于 2018-11-07T22:50:23.493 回答