Search code examples
c++arraysc++11template-meta-programmingconstexpr

Variable length array error with constexpr


I have a class with a member function which declares an array whose size is based off a formula.

template <int SIZE>
class Example{
   constexpr int lookup(const int n) const
   {
      return n * n + n;
   }
   inline void func()
   {
       double array[lookup(SIZE)];
   }
};

This gives me the vla error. I think it should work because SIZE is resolved at compile time, and lookup is a constexpr. I know the following will work:

template <int SIZE>
class Example{

   inline void func()
   {
       constexpr int sz = SIZE * SIZE + SIZE;
       double array[sz];
   }
};

I guess I'm just trying to figure out why

EDIT Sorry for the typos, was trying to just write a smaller example and ended up with the missing n and class name.


Solution

  • It's complicated...

    First of all, some compilers (see MikeCAT answer and Bill Lynch linked example) can compile the following code (if you give a name to the class and correct lookup() naming n the argument)

    inline void func()
    {
        double array[lookup(SIZE)];
    }
    

    because they support a C99 extension that accept the "variable length array" feature.

    But this extension isn't standard C++.

    You can verify this modifying func() as follows (almost equivalent, in standard C++)

    inline void func()
    {
        constexpr int s = lookup(SIZE);
    
        double array[s];
    }
    

    and this can't compile if lookup() is a non-static method

    Consider that

     lookup(SIZE);
    

    is a short form for

     this->lookup(SIZE);
    

    I mean... the use of lookup() involve an object of your class.

    The problem is that your func() method is available for both constexpr and non-constexpr objects.

    Suppose you have a non-constexpr object: calling func() from it you impose that

    constexpr int s = this->lookup(SIZE);
    

    is evaluated compile-time.

    That is: you impose that the this pointer (so the object itself) is available compile-time.

    This is clearly impossible for run-time created objects, so your code can't compile.

    Different if you declare lookup() as a static method: this way, calling lookup() doesn't involve an object of your class so your code can compile.