Reputation: 306
I'd like to build a compile time lookup table using c++14 variadic templates. At the moment I'm there:
static const unsigned kCount = 5;
template<unsigned Index>
constexpr auto getRow(void)
{
return std::array<unsigned, 2> { Index, Index * Index };
}
template<unsigned... Indices>
constexpr auto generateTable(std::index_sequence<Indices...>)
{
return std::array<std::array<unsigned, 2>, sizeof...(Indices)>
{
// This is were I'm stuck. How to build a std::array using Indices as template parameter in getRow()?
};
}
constexpr auto generate(void)
{
return generateTable(std::make_index_sequence<kCount>{});
}
I want the table to be in a std::array
. Each row consists of a std::array
with 2 columns. I'm stuck in generateTable()
where I need to somehow pass my Indices to getRow()
as a template parameter.
Is this achievable using std::integer_sequence
and template parameter pack expansion or do I need to implement the recursion on my own?
(getRow()
is simplified - the value types are actually coming from templated types. Index * Index
is just a placeholder. I need to know the way how to call getRow()
using parameter pack expansion.)
Upvotes: 3
Views: 951
Reputation: 66200
+1 for the solution of KyleKnoepfel but I have problems compiling your code in my amd64 linux because "error: no matching function for call to 'generateTable'" and "candidate template ignored: substitution failure : deduced non-type template argument does not have the same type as the its corresponding template parameter ('unsigned long' vs 'unsigned int')"
The problem is that std::make_index_sequence<kCount>{}
generate a sequence of std::size_t
. If std::size_t
is defined as unsigned int
, all goes well; if (like in my platform) std::size_t
is defined as unsigned long
, the following declaration didn't work
template<unsigned... Indices>
constexpr auto generateTable(std::index_sequence<Indices...>)
Suggestion: use ever std::size_t
instead unsigned
; particularly
template<std::size_t ... Indices>
constexpr auto generateTable(std::index_sequence<Indices...>)
En passant, initialize a std::array
with { val1, val2 }
(only one level of braces) it's perfectly legal in C++14 but (IMHO) I think it's better to use the old (C++11) syntax with a double level of braces ({ { val1, val2 } }
); this for backwards compatibility (as pointed by Wum) and to avoid annoying warnings with some compilers (like clang++ 3.5). So I suggest to use a second level of braces in array declaration/initialization, so
return std::array<unsigned, 2> { { Index, Index * Index } };
and
return std::array<std::array<unsigned, 2>, sizeof...(Indices)>
{ { getRow<Indices>() ... } };
p.s.: sorry for my bad English.
Upvotes: 4
Reputation: 1698
Looks like you're almost there. Just rely on parameter-pack expansion:
return std::array<std::array<unsigned, 2>, sizeof...(Indices)>
{
getRow<Indices>()...
};
where the getRow<Indices>()...
line will expand to:
getRow<0>(), getRow<1>(), ..... , getRow<sizeof...(Indices)-1>()
Upvotes: 9