Constexpr, patterns and array size

I would like to pass the template argument to the function call, and use the return value as the size of the array, i.e.

constexpr int myPow(int a, int b){ int result = 1; for(int i=0;i<b;i++) result *= a; return result; } template <int N> class testClass{ public: testClass(){} int array[myPow(2,N)]; }; int main(){ testClass<3> A; return 0; } 

compiler errors:

 ~ $ g++-4.6 test.cpp -std=gnu++0x test.cpp: In function 'constexpr int myPow(int, int)': test.cpp:6:1: error: body of constexpr function 'constexpr int myPow(int, int)' not a return-statement test.cpp: At global scope: test.cpp:12:23: error: array bound is not an integer constant before ']' token 

Any idea how to get around this?

+4
source share
3 answers

In C ++ 11, the constexpr function can only contain a return (see here for full details), so your myPow function myPow not constexpr-compatible (because it contains a for loop).

You can use this metafound to calculate integer power at compile time:

 template <int N, typename Type> constexpr Type pow(const Type& x) { return (N > 1) ? (x*pow<(N-1)*(N > 1)>(x)) : ((N < 0) ? (static_cast<Type>(1)/pow<(-N)*(N < 0)>(x)) : ((N == 1) ? (x) : (static_cast<Type>(1)))); } 

If you want to calculate 2^N , you can enter:

 pow<N>(2) 

Note 1: this metafung is very general and also works for negative integers and floating point types, so you can enter: pow<-3>(3.14)

Note 2: multiplying by N>1 or N<0 in the pattern is here to block infinite recursion and make the pattern parameter be zero when the branch does not matter. This can be done using specialized specialization, but the technique used here allows you to write one function.

+7
source

In C ++ 11, constexpr functions constexpr quite limited, and your code does not comply with the restrictions (you cannot declare variables, mutate the local state and not use most forms of operators - including loops), however C ++ 1y removes most of the restrictions, and Clang 3.3 accepts source code sample in -std=c++1y mode.

If you need code to work in C ++ 11 mode, you can rewrite it to circumvent the limitations of constexpr :

 constexpr int myPow(int a, int b) { return b ? a * myPow(a, b - 1) : 1; } 
+7
source

EDIT: Richard Smith's finished answer.

There is no need to use metafunction according to your answer to implement your myPow algorithm as a constexpr -qualified function.

You can simply specify the exponent argument = 0, and then:

 constexpr int myPow(int a, int b = 0){ return b == 0 ? 1 : myPow(a,b - 1) * a; } 

If you do not like the default on this argument, then otherwise you can default this argument to the constexpr helper element, which myPow simply calls, for example,

 namespace impl { constexpr int myPow(int a, int b = 0){ return b == 0 ? 1 : myPow(a,b - 1) * a; } } constexpr int myPow(int a, int b){ return impl::myPow(a,b); } 

If and when you upgrade to at least gcc 4.7.2, you can -std=c++11 even to hide this auxiliary device inside myPow , because you will be allowed to define types inside the body of the constexpr function:

 constexpr int myPow(int a, int b){ struct _1 { static constexpr int _2(int a, int b = 0) { return b == 0 ? 1 : _2(a,b - 1) * a; } }; return _1::_2(a,b); } 

(although I think that strictly this latitude is an extension of C ++ 1y).

You might want to adapt the Vincent superior algorithm so that it is no longer a metaphone in N , but is still common to the arithmetic type.

+2
source

Source: https://habr.com/ru/post/1490063/


All Articles