0

I was working on a template function with non-type parameters (to avoid dynamic allocation of arrays) when a number of questions arose. My first question regards compile-time variable assignment. This arose from the following attempts at calls to the template function:

template<int n>
int *getDegrees(int A[][n]) {
  //return degrees
}

int main(int argc, char **argv) {
  int n = 10;
  int A[n][n];
  int *degs = getDegrees<n>(A);
}

Here, we have two errors: first, the compiler is unable to resolve the call to getDegrees(A):

main.cc:27: error: no matching function for call to ‘getDegrees(int [(((long unsigned int)(((long int)n) + -0x00000000000000001)) + 1)][(((long unsigned int)(((long int)n) + -0x00000000000000001)) + 1)])’

Second, we're unable to use n in the template call as it isn't a constant expression. Simply making n constant does resolve the issues

const int n = 10;

however, if I were to do

int m = 10;
const int n = m; 

we get the same errors. While the second assignment may be allowed by the compiler, is it considered bad form to do so? Additionally, why would making n constant make a difference in resolving the function call?

My other question regards vlas: is memory allocated for them on the stack or the heap (and is this compiler-dependent)? There appears to have been some controversy in even allowing them in C++, should they be avoided in favor of vectors (or similar containers)?

Appreciate any insight!

glinka
  • 337
  • 3
  • 13
  • 2
    VLAs aren't C++. Do you want C answers? – Carl Norum Jul 15 '13 at 18:36
  • Interesting, my GNU C++ compiler has no problems with vlas, I wasn't aware they were a C construct. C answers would be fine though, thanks for the heads-up! – glinka Jul 15 '13 at 19:03
  • If you want dynamic stack allocation, you can always try alloca(). – Michael Dorgan Jul 15 '13 at 19:04
  • If vlas are allocated dynamically on the stack, then g++ appears to do so without needing an explicit call to alloca(). – glinka Jul 15 '13 at 19:15
  • 1
    @glinka: While the compiler allows VLAs in C++, they are not arrays in the same sense that regular arrays. Their type is not fully known at compile time (the size is part of the type in C++), and thus they cannot be used in templates. – David Rodríguez - dribeas Jul 15 '13 at 19:16

1 Answers1

5

I will try to answer whatever I could get from your question.
You can change the function prototype to receive the array by reference:

template<size_t n> // see the type
int *getDegrees(int (&A)[n][n]) {  // see the signature
  // ...
}

In above code, we are leveraging the fact that the array has same dimensions.
However, in general case it should be:

template<size_t n1, size_t n2> // see the type
int *getDegrees(int (&A)[n1][n2]) {  // see the signature
  // ...
}

If the size is too big then an error is issued by the compiler to inform you. e.g. (from g++):

error: size of array ‘A’ is too large

Now coming to the other question regarding the difference between assignment of the constant integer.
In C++, the array size has to be compile time constant and

const int n = 10;

fulfills that requirement. Because the compiler can make out that, 10 is a literal number being assigned to n.

In case of,

int m = 10;
const int n = m;

Compiler finds out that the source of n is not a compile time constant itself. And thus it makes the code ill formed.

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • While ill-formed, n appears to behave as expected (it is assigned the unchangeable value of 10). Should such constructs nonetheless be avoided? – glinka Jul 15 '13 at 19:45
  • 1
    @glinka: G++ has a nonconforming extension allowing VLAs (arrays whos bounds are not compile time constant), but even G++ requires template parameters to be compile time constants. I'd avoid them. – Mooing Duck Jul 15 '13 at 19:50