哪个编译器(如果有)在参数包扩展中存在错误? [英] Which compiler, if any has a bug in parameter pack expansion?

查看:157
本文介绍了哪个编译器(如果有)在参数包扩展中存在错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当尝试使用方便的方法将元组作为容器访问时,我编写了一个测试程序.

When experimenting with convenient ways to access tuples as containers, I wrote a test program.

在clang(3.9.1和Apple clang)上按预期进行编译,从而产生预期的输出:

on clang (3.9.1, and apple clang) it compiles as expected, producing the expected output:

1.1
foo
2

在gcc(5.4,6.3)上,它无法编译:

on gcc (5.4, 6.3), it fails to compile:

<source>: In lambda function:
<source>:14:61: error: parameter packs not expanded with '...':
             +[](F& f, Tuple& tuple) { f(std::get<Is>(tuple)); }...
                                                             ^
<source>:14:61: note:         'Is'
<source>: In function 'decltype(auto) notstd::make_callers_impl(std::index_sequence<Is ...>)':
<source>:14:64: error: expansion pattern '+<lambda>' contains no argument packs
             +[](F& f, Tuple& tuple) { f(std::get<Is>(tuple)); }...
                                                                ^~~
Compiler exited with result code 1

问题:谁是对的?可以解决吗?

Question: who is right? Can it be fixed?

程序:

#include <iostream>
#include <array>
#include <tuple>

namespace notstd {

    template<class F, class Tuple, std::size_t...Is>
    auto make_callers_impl(std::index_sequence<Is...>) -> decltype(auto)
    {
        static std::array<void (*) (F&, Tuple&), sizeof...(Is)> x =
        {
            +[](F& f, Tuple& tuple) { f(std::get<Is>(tuple)); }...
        };
        return x;
    };

    template<class F, class Tuple>
    auto make_callers() -> decltype(auto)
    {
        return make_callers_impl<F, Tuple>(std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>());
    };

    template<class Tuple, std::size_t N = std::tuple_size<std::decay_t<Tuple>>::value >
    struct tuple_iterator {
        static constexpr auto size = N;

        constexpr tuple_iterator(Tuple& tuple, std::size_t i = 0) : tuple(tuple), i(i) {}

        template<class F>
        void with(F&& f) const {
            static const auto& callers = make_callers<F, Tuple>();
            callers[i](f, tuple);
        }

        constexpr bool operator!=(tuple_iterator const& r) const {
            return i != r.i;
        }

        constexpr auto operator++() -> tuple_iterator& {
            ++i;
            return *this;
        }


        Tuple& tuple;
        std::size_t i;
    };

    template<class Tuple>
    auto begin(Tuple&& tuple)
    {
        return tuple_iterator<Tuple>(std::forward<Tuple>(tuple));
    }

    template<class Tuple>
    auto end(Tuple&& tuple)
    {
        using tuple_type = std::decay_t<Tuple>;
        static constexpr auto size = std::tuple_size<tuple_type>::value;
        return tuple_iterator<Tuple>(std::forward<Tuple>(tuple), size);
    }

}

template<class T> void emit(const T&);

int main() {
    auto a = std::make_tuple(1.1, "foo", 2);
    auto i = notstd::begin(a);
    while(i != notstd::end(a))
    {
        i.with([](auto&& val) { std::cout << val << std::endl; });
        ++i;
    }
}

推荐答案

这是 gcc错误47226 . gcc根本不允许这样生成lambda的pack扩展.该错误仍存在于7.0中.

This is gcc bug 47226. gcc simply does not allow producing a pack expansions of lambdas like that. The bug is still present in 7.0.

在这种情况下,您实际上并不需要lambda,而只需创建一个功能模板即可:

In this case, you don't really need the lambda and can just create a function template:

template <size_t I, class F, class Tuple>
void lambda(F& f, Tuple& tuple) {
    f(std::get<I>(tuple));
}

static std::array<void (*) (F&, Tuple&), sizeof...(Is)> x = 
{
    lambda<Is,F,Tuple>...
};   

这篇关于哪个编译器(如果有)在参数包扩展中存在错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆