# Array of constant values as template parameter

• September 19th, 2011, 07:36 AM
dude_1967
Array of constant values as template parameter
Hello,

It's been a while since I checked in here.

Is it possible to use an array of constant values as a template parameter. I am writing preliminary benchmark code for ISO/IEC 14882:2011, so I could also use std::array or std::initializer_list.

In the mathematical template below, I use integer coefficients. The template has order 3.

Code:

```template<const std::size_t order,         const std::uint_least16_t B0,         const std::uint_least16_t B1,         const std::uint_least16_t B2,         const std::uint_least16_t B3> struct order3_math {   // Do order-3 math. };```
If I want to write more generic code, I could use order N and an array-type template parameter. But it does not work with compilers like VS2010 and GCC 4.6.x. Can it work or *should* something like this ever work without variadic templates?

Code:

```// Can I do anything like this? template<const std::size_t order,         const std::array<std::uint_least16_t, order> coefficients> struct orderN_math {   // Do order-N math. };```
Thank you.
Sincerely, Chris.
• September 19th, 2011, 08:07 AM
superbonzo
Re: Array of constant values as template parameter
AFAIK, you can declare non type template parameters of array type, provided they have external linkage. Something like

Code:

```template<std::size_t order, std::uint_least16_t coefficients[order]> struct orderN_math {         // ... }; int a[3]; orderN_math<3,a> b;```
is this what you're looking for ? I ask, because IMHO if the intent is to emulate variadic templates then a boost MPL based solution would be better ...
• September 19th, 2011, 08:48 AM
dude_1967
Re: Array of constant values as template parameter
No, that one did not work.

But this cool tidbit works with GCC. I tested it with GCC 4.5.2

Code:

```#include <initializer_list> template<const unsigned order> struct orderN_math {   static unsigned do_math(const std::initializer_list<unsigned>& coefficients)   {     return std::accumulate(coefficients.begin(), coefficients.end(), 0u);   } }; const unsigned sum = orderN_math<3u>::do_math({ 1u, 3u, 3u, 1u });```
VS2010 does not yet support <initializer_list>. But I don't really need it, as I'm using GCC.

Not exactly what I wanted, but a good start nonetheless.

At this time, I am investigating compiler efficiency for real-time embedded systems using solely pure language attributes and would prefer not to bind anything from boost into this investigation.

Thanks, Chris.
• September 19th, 2011, 09:23 AM
monarch_dodra
Re: Array of constant values as template parameter
Quote:

Originally Posted by dude_1967
No, that one did not work.

But this cool tidbit works with GCC. I tested it with GCC 4.5.2

Code:

```#include <initializer_list> template<const unsigned order> struct orderN_math {   static unsigned do_math(const std::initializer_list<unsigned>& coefficients)   {     return std::accumulate(coefficients.begin(), coefficients.end(), 0u);   } }; const unsigned sum = orderN_math<3u>::do_math({ 1u, 3u, 3u, 1u });```
VS2010 does not yet support <initializer_list>. But I don't really need it, as I'm using GCC.

Not exactly what I wanted, but a good start nonetheless.

At this time, I am investigating compiler efficiency for real-time embedded systems using solely pure language attributes and would prefer not to bind anything from boost into this investigation.

Thanks, Chris.

Not sure what you are trying to do. Can't you do the same with a plain old point, or a reference to a fixed size array?

Code:

```#include<iostream> #include<algorithm> #include<numeric> template<const unsigned order> struct orderN_math {   //ONLY accepts arrays, and only of size4.   static unsigned do_math1(const unsigned int (&coefficients) [order])   {     return std::accumulate(coefficients, coefficients+order, 0u);   }   //Accpets anything, you are responsible for making sure it is the right type.   static unsigned do_math2(const unsigned int* coefficients)   {     return std::accumulate(coefficients, coefficients+order, 0u);   } }; int main() {   unsigned a[] = {1u, 3u, 3u, 1u};   unsigned* p = a;   const unsigned sum11 = orderN_math<4u>::do_math1(a);   //const unsigned sum12 = orderN_math<4u>::do_math1(p);   const unsigned sum21 = orderN_math<4u>::do_math2(a);   const unsigned sum22 = orderN_math<4u>::do_math2(p); }```
• September 19th, 2011, 09:47 AM
dude_1967
Re: Array of constant values as template parameter
Quote:

Originally Posted by monarch_dodra
Not sure what you are trying to do. Can't you do the same with a plain old point, or a reference to a fixed size array?

With pointer : Yes and no.
With std::array : Yes.

I am simultaneously investigating compiler-time unrolling in combination with compiler-time constants. The constants in a const std::initializer_list or a const std::array can be easily identified by the compiler and used in constant folding. They are also available for forced loop-unrolling with meta-programming.

The constants in a pointer are less available to the compiler.

These investigations go deep into compiler optimization methods. It's not really about finding the most terse code, rather the combination of terse, unrollable and ultra-fast.

Sincerely, Chris.
• September 19th, 2011, 10:07 AM
monarch_dodra
Re: Array of constant values as template parameter
Quote:

Originally Posted by dude_1967
The constants in a pointer are less available to the compiler.

Well, an initializer list is a convenience class that can be used to uniformly initialize containers, or pass arguments. While the compiler can inline its construction, and knows its size, once passed as an argument, it is a pure run-time object, no different than, say, a vector.

the template parameter "order" is a compile time constant that can be exploited by the compiler (and the one used in my code), to exploit loop unrolling. "coefficients.begin(), coefficients.begin() + order" can be unrolled. "coefficients.begin(), coefficients.end()" can't be unrolled though...

If you were to use and std::array though, then it would work, but you would HAVE to make do_math a sub-template:

Code:

```#include <array> #include<numeric> template<unsigned order> struct orderN_math {   template<const unsigned order2>   static unsigned do_math(const std::array<const unsigned, order2>& coefficients)   {     return std::accumulate(coefficients.begin(), coefficients.begin() + order2, 0u);   } }; int main() {   std::array<const unsigned, 4> a{ 1u, 3u, 3u, 1u };   const unsigned sum = orderN_math<2u>::do_math(a); }```
• September 19th, 2011, 10:28 AM
dude_1967
Re: Array of constant values as template parameter
Quote:

Originally Posted by monarch_dodra
initializer list... once passed as an argument, it is a pure run-time object...

the template parameter "order" is a compile time constant that can be exploited by the compiler...

If you were to use and std::array though, then it would work, but you would HAVE to make do_math a sub-template:

Yes. I agree, I agree and I agree with all three sections of your text.

And I really do like your C-style array suggestion. In fact, I'm just in the process of seeing how it is unrolled or even forcing the unroll.

Thank you.

Sometimes I take the exercise even further by *forcing* loop unrolling using meta-programming for things like accumulation and inner products. And this is what I am also looking at. It's pretty amazing what these C++ compilers can do. They really squeeze the code at high optimization level. Fascinating.

Thank you.
Sincerely Chris.
• September 19th, 2011, 10:33 AM
dude_1967
Re: Array of constant values as template parameter
Oh yeah,

And I also forgot to add that one of the real tricks is finding reliable ways to coerce the compiler into constant-folding the coefficients, not merely getting the math unrolled. This allows fast shift-and-add instead of multiply when, for example, dealing with an inner product.

Some ultra-clever compilers like GCC will *know* the constant values of an initializer list if these are passed as compile-time constants to the subroutine in curly braces.

Again, simply great compiler technologies these days. I can play all day and still find new stuff.

Sincerely, Chris.