2

I have the following code which could not be complied.

using namespace std;
void f(int);
template<typename T1, size_t N>
void array_ini_1d(T1 (&x)[N])
{
  for (int i = 0; i < N; i++)
  {
    x[i] = 0;
  }
}

What is the proper way to pass the array if the main is something like below.

int main()
{
  int a;
  cin >> a;
  int n = a / 4;
  f(n);
  return 0;
}

void f(int n)
{
  int arr[n];
  array_ini_1d(arr);
}

error: no matching function to call to array_ini_1d..............

M.M
  • 138,810
  • 21
  • 208
  • 365
user29561
  • 41
  • 5
  • 2
    What error do you get? Note that you can zero-initialize the elements of the array like this: `int arr[10] = {};` – juanchopanza Feb 13 '14 at 07:39
  • 1
    Shouldn't be anything wrong with the code as long as `size_t` is defined. As the question stands now, the answer is 'that is the correct way'. More info is needed to diagnose the problem. –  Feb 13 '14 at 07:42
  • Compiles for me. What error do you have? What compiler do you use? – Sergii Khaperskov Feb 13 '14 at 07:46
  • You need to include e.g. `` for `size_t` (or `` and say `using std::size_t`) to guarantee that your code sample compiles without further changes. – juanchopanza Feb 13 '14 at 07:47
  • i'm calling this function inside another function. is it ok? – user29561 Feb 13 '14 at 07:49
  • 1
    @user29561 Yes, that is OK. Please post a simple code sample that reproduces the problem. Otherwise we're just guessing :) – juanchopanza Feb 13 '14 at 07:52
  • error:no matching func to call to – user29561 Feb 13 '14 at 08:09
  • Two things: you are missing a `;` at the declaration `void f(int)`, and the standard does not support automatic storage arrays with a runtime determined size, although your compiler *might* allow it as an extension. – juanchopanza Feb 13 '14 at 08:15

6 Answers6

2

I don't think the compiler can deduce the size of a variable-length array in a template. Also, don't forget to forward declare f before you use it. Variable-length arrays are a GCC extension and you should get a warning regarding their use.

  • 2
    I don't think `iostream` is guaranteed to define `size_t`. – juanchopanza Feb 13 '14 at 07:53
  • @juanchopanza Maybe. I found this in the standard (not sure if it's out of context): `However, referring to std or std::size_t is ill-formed unless the name has been declared by including the appropriate header. — end note ] ` –  Feb 13 '14 at 07:56
  • As per the standard `std::size_t` is defined in `` (usualy as the same as `::size_t` in ``. iostrem often use it, but the standard does not require `streampos` to be the same (or compatible with...) size_t. It is just a very common immplementation on platform having size_t as 64 bit unsigned, but not a standard requirement. So, in fact "iostream" does not grant for size_t to be defined – Emilio Garavaglia Feb 13 '14 at 08:03
  • @Emilio It seems this answer is invalidated with the new edit anyway. –  Feb 13 '14 at 08:04
  • The point is that `std::size_t` may even not be the same as `::size_t`, although no implementer will ever make them distinct, otherwise the most of the existing cod will break... – Emilio Garavaglia Feb 13 '14 at 08:07
  • But since arrays are from C and the size is the difference of two pointers, the proper way to describe it is `::size_t` and not `std::size_t`, wich is much more related as a bridge towards traits classes, allocators and containers – Emilio Garavaglia Feb 13 '14 at 08:10
  • @Emilio I thought `` just includes `` and then wraps it into `std`. As long as the OP doesn't use `using namespace std;`, there should be no conflicts, right? –  Feb 13 '14 at 08:14
  • @remyabel: yes, this is what all the implementations do. But that's not a specification: the C++ standard doesn't say where `std::size_t` must come from. It just says it "must be wide enough to measure the distance of two pointers". C does the same for `::size_t`, but there is nothing is the specification requirement that says they have to be the same – Emilio Garavaglia Feb 13 '14 at 08:25
2

The problem is that variable size arrays are not supported by c++, and is only supported as compilers extension. That means, the standard doesn't say what should happen, and you should see if you can find in compiler's documentation, but I doubt that such corner cases are documented.

So, this is the problem :

int arr[n];

The solution is to avoid it, and use something supported by c++, like for example std::vector.

BЈовић
  • 62,405
  • 41
  • 173
  • 273
1

You may declare your function like this:

template <typename A, size_t N> void f(A a[N]) {
    for(size_t i = 0; i < N; i++)
        cout << a[i];
}

However, the problem is that when you call the function, the compiler won't deduce the template parameters, and you will have to specify them explicitly.

char arr[5] = {'H', 'e', 'l', 'l', 'o'};

int main()
{
    //f(arr); //Won't work
    f<char, sizeof(arr)/sizeof(arr[0])>(arr);
    cout << endl;
    return 0;
}

Unfortunately, that ruins the very idea...

UPD: And even that code does NOT work for an array that has variable length, for the length is calculated at runtime, and the template parameters are defined at compilation time.

UPD2: If using std::vector you may create it initialized: vector<int> arr(n, 0); Or you may fill it with fill from <algorithm> when needed: std::fill(arr.begin(), arr.end(), 0);

Ellioh
  • 5,162
  • 2
  • 20
  • 33
  • Well yeah, the OP is trying to create a local VLA. He's passing the size of the array to the function anyway, so why can't just pass it along to `array_ini_1d`? There's no reason for the templates except for the deduction trick, which is defeated by the usage of VLAs. –  Feb 13 '14 at 08:20
1

As you use Variable length array (VLA) (compiler extension), compiler cannot deduce N.

You have to pass it by pointer and give the size:

template<typename T>
void array_ini_1d(T* a, std::size_t n)
{
    for (std::size_t i = 0; i != n; ++i) {
        a[i] = 0;
    }
}

void f(int n)
{
    int arr[n];
    array_ini_1d(arr);
}

Or use std::vector. (no extension used so). Which seems cleaner:

template<typename T>
void array_ini_1d(std::vector<T>& v)
{
    for (std::size_t i = 0, size = v.size(); i != n; ++i) {
        a[i] = 0; // or other stuff.
    }
}

void f(int n)
{
    std::vector<int> arr(n); // or arr(n, 0).
    array_ini_1d(arr);
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
1

Template parameters must be resolved at compile-time.

There is no way that a function template with parameter size_t N can match any sort of array or other container whose size comes from a run-time input.

You will need to provide another version of the array_1d_ini which does not have the size as a template parameter.

M.M
  • 138,810
  • 21
  • 208
  • 365
-1
template<typename T, size_t N>
void f(T* a)
{
/* add your code here */
}

int main()
{
    int a[10];
    f<int, 10>(a);
    return 0;
}
jeffw
  • 11
  • 2