4

I would like to pass template argument to function call and the return value use as size of an array ie

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?

5
  • 3
    Your function cannot be more than one return ...; (until C++14) that only uses compile-time tools or it won't give back a compile-time constant. Commented Jul 6, 2013 at 20:28
  • Well post the relevant code (i.e. the one in myPow and a minimal complete testClass, and the actual compiler error. Commented Jul 6, 2013 at 20:40
  • Did you actually forward-declare myPow()? Is a function prototype for it known at the time you use it in testClass? Commented Jul 6, 2013 at 20:47
  • I added the whole "working" code. Commented Jul 6, 2013 at 20:49
  • 1
    OK then, It's what chris said. Your constexpr function is not allowed to be more than a single return statement in C++11. The compiler error message already makes that apparent. Commented Jul 6, 2013 at 20:50

3 Answers 3

7

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

You can use this metafunction to compute the 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 compute 2^N, you can type:

pow<N>(2)

Note 1: this metafunction is very generic and also work for negative integers and floating-point types, so you can type : pow<-3>(3.14)

Note 2: the multiplication by N>1 or N<0 in the template are here to block infinite recursivity and force the template parameter to be equal to zero when the branch is not relevant. This could be done with template specialization, but the technique used here allow to write a single function.

Sign up to request clarification or add additional context in comments.

4 Comments

Wow very nice! I was thinking about using metafunction but couldn't figure out how.
Yes it is very generic and I really love it!!! Probably I'll give you some reward in 2 day if I don't forget about it ;)
But I would like to know why there is (N>1) and (N<0) in pow<(N-1)*(N > 1)> and pow<(-N)*(N < 0)>(x) ? It seams to me to be redundant.
Because when you write metafunctions, the compiler will try to instantiate all the branches even if they are not executed. So without this redudancy, the recursivity will not stop. So the N>1and N<0 are here to force the template parameter to be equal to zero to avoid infinite recursivity. I will detail it in the answer.
7

In C++11, constexpr functions are quite restricted, and your code doesn't comply with the restrictions (you can't declare variables, mutate local state, nor use most forms of statements -- including loops). However, C++1y removes most of the restrictions, and Clang 3.3 accepts your original code sample in its -std=c++1y mode.

If you need the code to work in C++11 mode, you can rewrite it to sidestep the constexpr restrictions:

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

Comments

2

EDIT: Goto Richard Smith's smarter answer.

It is not necessary to use a metafunction, as per your accepted answer, to implement your myPow algorithm as a constexpr-qualified function.

You can just default 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 defaulting that argument, then alternatively you can default that that argument in a constexpr auxiliary which myPow just invokes, e.g.

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 at least to gcc 4.7.2 you would be able with -std=c++11 even to hide that auxiliary within myPow itself, because you will be allowed to define types within the body of a 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 strictly this latitude is a C++1y extension).

You might want to adapt Vincent's superior algorithm so that it is no longer a metafunction in N, but is still generic at to the arithmetic type.

3 Comments

The default argument is not necessary.
@RichardSmith Ha! How right you are! I will chop it accordingly.
@RichardSmith. ...no I won't chop it as I see that would now be copying your better answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.