将constexpr数组扩展为一组非类型模板参数

Pav*_*nko 9 c++ templates template-meta-programming variadic-templates constexpr

假设我有一个编译时constexpr数组和一个可变参数类模板,其中包含一组与数组元素相同类型的非类型参数.

我的目标是使用数组中的值实例化类模板:

struct Container
{
    int containee[3];
};

constexpr Container makeContainer();

template <int... Elements> class Foo;

Foo<makeContainer().containee[0],
    makeContainer().containee[1],
    makeContainer().containee[2]> foo;
Run Code Online (Sandbox Code Playgroud)

上面的代码效果很好.但是,每当我需要实例化Foo模板时,我都不得不手动索引数组.我想编译器自动为我做这件事:

Foo<Magic(makeContainer().containee)> foo;
Run Code Online (Sandbox Code Playgroud)

我在cppreference做了一些RTFM,但这没有帮助.我知道std::forward<>(),但它不能应用于模板参数列表.

Vit*_*meo 7

  1. 改变makeContainer到一个struct与一个constexpr operator()或一个constexpr拉姆达(C++ 17) .函数指针在这里不起作用.

    struct makeContainer
    {
        constexpr auto operator()() const
        {
            return Container{/* ... */};
        }
    };
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用std::make_index_sequencestd::index_sequence生成索引的编译时序列:

    template <typename C>
    constexpr auto fooFromContainer(const C& container)
    {
        return fooFromContainerImpl(container, std::make_index_sequence<3>{});
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 通过创建一个新的constexpr容器实例C,然后展开序列以索引常量表达式中的元素:

    template <typename C, std::size_t... Is>
    constexpr auto fooFromContainerImpl(const C& container, std::index_sequence<Is...>)
    {
        constexpr auto c = container();
        return Foo<c.containee[Is]...>{};
    }
    
    Run Code Online (Sandbox Code Playgroud)

wandbox.org上的完整示例


只是为了好玩,这是一个C++ 20实现:

struct container { int _data[3]; };

template <int... Is> 
struct foo 
{ 
    constexpr auto t() const { return std::tuple{Is...}; }
};

template <typename C>
constexpr auto foo_from_container(const C& c)
{
    return []<std::size_t... Is>(const auto& c, std::index_sequence<Is...>)
    {
        return foo<c()._data[Is]...>{};
    }(c, std::make_index_sequence<3>{});
}

int main()
{
    constexpr auto r = foo_from_container([]{ return container{42, 43, 44}; });   
    static_assert(r.t() == std::tuple{42, 43, 44});
}
Run Code Online (Sandbox Code Playgroud)

wandbox.org上的实例

  • 可以使用`std :: make_index_sequence <std :: size(container().containee)>`而不是`std :: make_index_sequence <3>`. (2认同)