【问题标题】:Compile-time reversal of parameter-pack expansion参数包扩展的编译时反转
【发布时间】:2017-11-15 18:25:25
【问题描述】:

在下面的类模板中,我想用 reverse-oder 中的参数包 vv 的值初始化成员数组 b

template<typename T>
struct Test {
public:
    template<typename... B>
    explicit Test(B... vv) : b{vv...,} // how to initialize member b with pack expansion v... in reverse order
    {
    }
private:
    std::byte b[sizeof(T)];
};

我无法想象如何在表单中反转参数包扩展,它也可以在初始化列表中使用。

【问题讨论】:

  • std::reverse(std::begin(b), std::end(b)); 怎么样?
  • 那是初始化后的runtime反转。
  • 否则你必须和std::index_sequence一起玩

标签: c++ variadic-templates


【解决方案1】:

使用委托构造函数,您可以执行以下操作:

template<typename T>
struct Test {
    template <std::size_t...Is, typename... B>
    Test(std::index_sequence<Is...>, B&&... vv) :
        b{std::get<sizeof...(Is) - 1 - Is>(std::tie(vv...))...}
    {}

public:
    template<typename... B>
    explicit Test(B... vv) : Test(std::index_sequence_for<B...>{}, vv...) {}
private:
    std::byte b[sizeof(T)];
};

【讨论】:

    【解决方案2】:

    鉴于 b 是一个非静态数据成员,以下更紧凑的版本在优化后可能会等效(*):

    template<typename T>
    struct Test {
    public:
        template<typename... B>
        explicit Test(B... vv){ auto rb = std::rbegin(b); ((*rb++ = vv),...); }
    private:
        char b[sizeof(T)];
    };
    

    (*) 除非 Jarod42 的解决方案在 constexpr...

    编辑:看起来trunk clang 和 gcc 都非常聪明地将反转的 B 放在 Jarod42 的代码和我的代码中的数据部分 both 中!

    【讨论】:

    • 看起来比 Jarod42 解决方案简单一点,但取决于编译器优化。谢谢!
    • @wimlopaan,从技术上讲,这两种解决方案都依赖于编译器优化(因为 b 不是 constexpr);实际上,据我所知,它们最终产生了相同的 asm ......也就是说,在这两种情况下都不会在运行时执行反转
    • @wimlopaan,事实上,std::tie 和 std::get 机制实际上可能会在假设的优化不佳的构建中变得更慢。唯一可以确定的方法是标记 Test ctor constexpr 并使用它来初始化 constexpr 对象或等效的东西......
    【解决方案3】:

    您使用index_sequence 以相反的顺序提取项目:

    #include <array>
    #include <iostream>
    #include <utility>
    #include <cstddef>
    
    template<::std::size_t... VIndexes> constexpr auto
    Make_ReversedArrayOfBytes_Impl
    (
        ::std::index_sequence<VIndexes...>
    ,   ::std::array<::std::byte, sizeof...(VIndexes)> bytes
    )
    {
        return
        (
            ::std::array<::std::byte, sizeof...(VIndexes)>
            {
                bytes[sizeof...(VIndexes) - 1 - VIndexes]...
            }
        );
    }
    
    template<typename... TItems> constexpr auto
    Make_ReversedArrayOfBytes(TItems... bytes)
    {
        return
        (
            Make_ReversedArrayOfBytes_Impl
            (
                ::std::make_index_sequence<sizeof...(TItems)>()
            ,   ::std::array<::std::byte, sizeof...(TItems)>
                {
                    static_cast<::std::byte>(bytes)...
                }
            )
        );
    }
    
    int main()
    {
        constexpr const auto items{Make_ReversedArrayOfBytes(0, 1, 2, 3, 4)};
        for(auto const & item: items)
        {
            ::std::cout << static_cast<::std::size_t>(item) << ::std::endl;
        }
        return 0;
    }
    

    Run in online compiler

    【讨论】:

      猜你喜欢
      • 2017-08-15
      • 1970-01-01
      • 2020-07-25
      • 1970-01-01
      • 2016-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多