如何在不升级到8.x的情况下解决GCC中的此参数扩展错误?

时间:2018-11-07 15:52:58

标签: c++11 c++14 compiler-bug gcc7 gcc8

考虑以下代码:

#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(实际上,如果您编写自己的std::index_sequence也是有效的C ++ 11)。但是-它无法使用g ++ 6.x和7.x进行编译;只有g ++ 8.x可以正确编译它(请参阅发生的on GodBolt)。

出于组织原因,我可以要求使用7.2之前的g ++版本。有什么办法可以在保留语义的同时更改代码,以使g ++ 7.x对其进行编译?

2 个答案:

答案 0 :(得分:2)

GCC的错误是它不能打包扩展lambda。因此,请勿打包扩展lambda。

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

答案 1 :(得分:0)

我用一块石头和expanded this visitation mechanism to functions taking an arbitrary number of arguments打了两只鸟。 whaddaya知道-这意味着将lambda移入辅助函数,以避免不同的参数包相互干扰。作为@ T.C。建议-这就是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)...);
};