9

Suppose I have a constexpr array (of known bound) of static storage duration:

constexpr T input[] = /* ... */;

And I have an output class template that needs a pack:

template<T...> struct output_template;

I want to instantiate output_template like:

using output = output_template<input[0], input[1], ..., input[n-1]>;

One way to do this is:

template<size_t n, const T (&a)[n]>
struct make_output_template
{
    template<size_t... i> static constexpr
    output_template<a[i]...> f(std::index_sequence<i...>)
    { return {}; };

    using type = decltype(f(std::make_index_sequence<n>()));
};

using output = make_output_template<std::extent_v<decltype(input)>, input>::type;

Is there a cleaner or simpler solution I am missing?

Constructor
  • 7,273
  • 2
  • 24
  • 66
Andrew Tomazos
  • 66,139
  • 40
  • 186
  • 319
  • what are you looking for? simpler interface or implementation? – TemplateRex Jul 03 '14 at 18:10
  • Could [the indices trick](http://loungecpp.wikidot.com/tips-and-tricks:indices) be useful here? You don't have a template index parameter to play with here, as you would with a tuple, but... – Lightness Races in Orbit Jul 03 '14 at 18:20
  • `using output = decltype(deduce(input))::unpack;`? Not much cleaner, though. – dyp Jul 03 '14 at 18:50
  • @dyp linkage of `a` seems to be the hurdle (even with more `constexpr` in appropriate places): http://coliru.stacked-crooked.com/a/2c196c6f2a82cbfb – TemplateRex Jul 03 '14 at 19:12
  • @TemplateRex That's what clang says ;) But indeed, addresses used as non-type template arguments must refer to objects with linkage, IIRC due to name mangling. The rule what is allowed as an address argument is very strict, it doesn't even allow derived-to-base conversions. – dyp Jul 03 '14 at 19:23
  • @TemplateRex: It's not that. It's just that you can't use a constexpr function parameter as a template argument, as it isn't a constant expression. `constexpr int f(int a) { constexpr int b = a; return b; } // ill-formed.` – Andrew Tomazos Jul 03 '14 at 19:27
  • @TemplateRex: A function call to a constexpr function (with constant arguments) is a constant expression, yes - however within the body of the contexpr function definition the parameters are not constant expressions. – Andrew Tomazos Jul 03 '14 at 19:32
  • 1
    It seems like this is another potential application of [proposal n3601](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3601.html), which would allow `using output = foo;` as far as I can see. – dyp Jul 03 '14 at 19:59
  • @dyp I though of an easier syntax to improve N3601: `template` where `V` is a compile-time **value** and the **type** can be easily accessed with `decltype(V)`. When I asked Mike and Daveed (the authors of N3601) about it, it turns out they also already came up with the exact same idea and syntax and want to prepare an updated version of N3601 :) – Daniel Frey Jul 09 '14 at 16:56
  • @DanielFrey ... I think I've seen this somewhere before.. but I cannot remember where or find it. Edit: maybe http://stackoverflow.com/q/5628121 or https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/fxGaLhamuFw – dyp Jul 09 '14 at 17:15
  • @dyp Looks like several people arrived at the same conclusion independently - which is IMHO a very good sign that this is the best syntax/solution :) – Daniel Frey Jul 09 '14 at 17:32

1 Answers1

9

Maybe you consider this to be cleaner:

template< const T* a, typename >
struct make_output_template;

template< const T* a, std::size_t... i >
struct make_output_template< a, std::index_sequence< i... > >
{
    using type = output_template< a[ i ]... >;
};

with

using output = make_output_template<
    input,
    std::make_index_sequence< std::extent_v< decltype( input ) > >
>::type;
Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
  • I do indeed sir, thanks. I guess all the examples of index_sequence I have seen use deduction of function parameters so I didn't think to use partial specicialization on the class. – Andrew Tomazos Jul 04 '14 at 11:05
  • There is no language specific feature that could stop me to try this using C++11, isn't? – Manu343726 Jul 11 '14 at 17:57
  • 2
    @Manu343726 Yes, you are right, all it needs it C++11 once you replaced `std::extend_v<...>` with `std::extend<...>::value` and you rolled your own version of `std::make_index_sequence`. – Daniel Frey Jul 11 '14 at 18:09