【问题标题】:Boost fusion fold-ing a parameter pack with a lambdaBoost fusion 使用 lambda 折叠参数包
【发布时间】:2015-08-07 21:39:07
【问题描述】:

在下面的代码中(C++14,没有来自 C++17 的“折叠”),我试图在编译时使用 boost fusion fold、参数包自动计算类字段的固定偏移量和一个 lambda。不幸的是,这会导致编译时错误......可以做这样的事情吗?

[编辑:其他事情也困扰着我:这不是我想要的。我希望 ControlledLayout2 的 _size 在编译时可用(这就是我将其设为静态的原因),而不仅仅是在调用构造函数时]

template <typename T, uint32_t size>
struct Field2
{
    typedef T _type;
    static const uint32_t _size;
    static uint32_t _offset;
};

template <typename T, uint32_t size>
const uint32_t Field2<T,size>::_size = size;

template <typename T, uint32_t size>
uint32_t Field2<T,size>::_offset = 0;

template <typename ... T>
struct ControlledLayout2
{
    static uint32_t _size;

    ControlledLayout2(T... args) {
      _size = fold({args...}, 0, 
                   [&](uint32_t s, T field) { return T::_offset = s + T::_size; }...);
    };
};

...
ControlledLayout2<Field2<int, 32>, Field2<char, 1>, Field2<long, 64>> cl;
cout << cl._size << endl;
...

而编译器错误是:

error: parameter not expanded with '...';
_size = accumulate({args...}, ...

【问题讨论】:

  • 错误看起来像 GCC。什么版本?
  • GCC 4.8.3.4 - 当然,有罪的是我的代码,而不是 GCC,对吧?
  • T field -> T 未展开
  • Piotr - 好的 - 但我很困惑 - 如果我在 T 和字段之间扩展 '...',编译器不会再在这个地方抱怨,但我想要一种类型在 lambda 体内的时间 - 这是它要做什么?
  • 那么你应该把 ... 放在 } 之后关闭 lambda 表达式(尽管它在 GCC 中失败)

标签: c++ templates boost lambda


【解决方案1】:

由于您想在编译时进行所有计算,boost::fusion::fold 不适合此操作。

相反,我会在ControlledLayout2 中使用constexpr 计算sizeoffset

#include <iostream>
#include <tuple>

template <typename T, uint32_t Size>
struct Field2
{
    using type = T;
    static const uint32_t size = Size;
};

template <typename T, typename U>
struct selector;

template <typename T, std::size_t... Is>
struct selector<T, std::index_sequence<Is...>>
{
    using type = std::tuple<typename std::tuple_element<Is, T>::type...>;
};

template <std::size_t N, typename... Ts>
struct remove_last_n
{
    using Indices = std::make_index_sequence<sizeof...(Ts)-N>;  
    using type = typename selector<std::tuple<Ts...>, Indices>::type;
};

template <typename ... Ts>
struct ControlledLayout2 
{    
    static constexpr uint32_t get_size()
    {
        return size_impl<Ts...>();
    }

    template <typename X, typename... Xs>
    static constexpr uint32_t size_impl(typename std::enable_if<(sizeof...(Xs) > 0)>::type* = 0)
    {
        return ((X::size) + size_impl<Xs...>());
    }

    template <typename X>
    static constexpr uint32_t size_impl()
    {
        return X::size;
    }

    template <std::size_t field_number>
    static constexpr uint32_t offset()
    {
        using Tuple = typename remove_last_n<sizeof...(Ts)-field_number, Ts...>::type;
        return offset_impl(Tuple{});
    }

    template <typename... Xs>
    static constexpr uint32_t offset_impl(std::tuple<Xs...>)
    {
        return size_impl<Xs...>();
    }

    static const uint32_t size = get_size();
};

int main()
{
    using Layout  = ControlledLayout2<Field2<int, 32>,
                                      Field2<char, 1>,
                                      Field2<char, 128>,
                                      Field2<long, 64>
                                      >;
    std::cout << Layout::size << std::endl;
    std::cout << Layout::offset<3>() << std::endl;
}

输出

225
161

live on coliru

【讨论】:

  • 在我的机器上,这似乎无法编译:错误:部分特化并不比主模板更特化,因为它用包扩展结构 remove_first_n
  • @Frank 哪个编译器?哪些编译器标志?
  • GCC 4.8.3.4 通过 cmake,没有特殊标志。
  • @Frank clang does not complain,然而g++ does。我改变了上面的实现,所以 g++ 和 clang 都很高兴
  • 谢谢! - 是否有 std::index_sequence 的标头? GCC 似乎无法按原样使用您的代码找到它...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-30
  • 1970-01-01
  • 1970-01-01
  • 2021-05-13
  • 2015-08-10
相关资源
最近更新 更多