padamowski
padamowski

Reputation: 159

How to pass an array of zero size to template function

I have an example function which takes a reference to an array. The number of elements in the function definition is unknown.

template<typename T, std::size_t N>
void someFun(T (&)[N])
{
    /* ... */
}

Calling this function for an array of one element is compiling fine. Deduced param type is int (&)[1].

int main()
{
    int arr[1];
    someFun(arr);
}

The problem is, when I'm trying to pass an array of zero elements. Example below shows the code and error.

int main()
{
    int arr[0];
    someFun(arr);
}

Compilation error (using g++ 7.2):

../src/main.cpp: In function 'int main()':
../src/main.cpp:24:13: error: no matching function for call to 'someFun(int  [0])'
someFun(arr);
         ^
../src/main.cpp:9:6: note: candidate: template<class T, long unsigned int N>  void someFun(T (&)[N])
void someFun(T (&a)[N])
  ^~~~~~~
../src/main.cpp:9:6: note:   template argument deduction/substitution failed:
make: *** [src/main.o] Error 1

I assume that deduced template param type is int (&)[0], however the substitution of this argument failed. I can go around by overloading someFun. Here is my working example:

template<typename T, std::size_t N>
void someFun(T (&)[N])
{
    /* ... */
}

template<typename T>
void someFun(T (&)[0])
{
    /* ... */
}

int main()
{
    int arr[0];
    someFun(arr);
}

Running this code leads to a call to void someFun(T (&)[0]) function and deduced param type is int (&)[0]. Could you please explain why I can't use more generic solution for an array of zero elements? Please don't judge the reason of this code. It is just an example for learning purposes.

Upvotes: 2

Views: 759

Answers (1)

Henri Menke
Henri Menke

Reputation: 10939

Arrays of zero size are definitely not standard C++. From [dcl.array]:

In a declaration T D where D has the form

D1 [ constant-expressionopt ] attribute-specifier-seqopt

[...]

If the constant-expression is present, it shall be a converted constant expression of type std​::​size_­t and its value shall be greater than zero.

GCC however provides arrays of zero length as an extension but since they are non-standard you can't expect them to work together with other language features, such as template argument deduction. You could make an explicit overload of the function for zero length arrays.

#include <cstdlib>

template<typename T, std::size_t N>
void someFun(T (&)[N]) {}

template<typename T>
void someFun(T (&)[0]) {}

int main() {
    int arr[0];
    someFun(arr);
}

This compiles on GCC (7.2.0) but not on Clang (6.0.0).

Upvotes: 2

Related Questions