简体   繁体   中英

Expanding a constexpr array into a set of non-type template parameters

Suppose I have a compile-time constexpr array and a variadic class template with a set of non-type parameters of the same type as the elements of the array.

My objective is to instantiate the class template with the values from the array:

struct Container
{
    int containee[3];
};

constexpr Container makeContainer();

template <int... Elements> class Foo;

Foo<makeContainer().containee[0],
    makeContainer().containee[1],
    makeContainer().containee[2]> foo;

The above code works well. However, I'm quite unhappy about having to manually index the array whenever I need to instantiate the Foo template. I would like the compiler to do that for me automatically:

Foo<Magic(makeContainer().containee)> foo;

I did some RTFM at cppreference, but that didn't help. I'm aware of std::forward<>() , but it cannot be applied to template argument lists.

  1. Change makeContainer to a struct with a constexpr operator() or a constexpr lambda (C++17) . A function pointer will not work here.

     struct makeContainer { constexpr auto operator()() const { return Container{/* ... */}; } };
  2. Use std::make_index_sequence and std::index_sequence to generate a compile-time sequence of the indices:

     template <typename C> constexpr auto fooFromContainer(const C& container) { return fooFromContainerImpl(container, std::make_index_sequence<3>{}); }
  3. Create a new constexpr container instance through C , then expand the sequence to index the elements in a constant expression:

     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]...>{}; }

complete example on wandbox.org


Just for fun, here's a C++20 implementation:

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

live example on wandbox.org

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM