-a #include <iostream>
-a struct S { static constexpr int N = -1; };
-a template <typename T> void foo(int [T::N])
-a {
-a-a-a std::cout << "array" << std::endl;
-a }
-a template <typename T> void foo(...)
-a {
-a-a-a std::cout << "..." << std::endl;
-a }
-a int main()
-a {
-a-a-a foo<int>(0);
-a }
GCC outputs "array", Clang and MSVC output "..."
-a-a #include <iostream>
-a-a struct S { static constexpr int N = -1; };
-a-a template <typename T> void foo(int [T::N])
-a-a {
-a-a-a-a std::cout << "array" << std::endl;
-a-a }
-a-a template <typename T> void foo(...)
-a-a {
-a-a-a-a std::cout << "..." << std::endl;
-a-a }
-a-a int main()
-a-a {
-a-a-a-a foo<int>(0);
-a-a }
GCC outputs "array", Clang and MSVC output "..."
You are taking an array by value.
This might not be the intention and
might take a slice.
Since the array index is unsigned -1 is UB or in
fact expand to UINT_MAX.
On Sun 3/1/2026 7:55 AM, Marcel Mueller wrote:
-a-a #include <iostream>
-a-a struct S { static constexpr int N = -1; };
-a-a template <typename T> void foo(int [T::N])
-a-a {
-a-a-a-a std::cout << "array" << std::endl;
-a-a }
-a-a template <typename T> void foo(...)
-a-a {
-a-a-a-a std::cout << "..." << std::endl;
-a-a }
-a-a int main()
-a-a {
-a-a-a-a foo<int>(0);
-a-a }
GCC outputs "array", Clang and MSVC output "..."
You are taking an array by value.
There's no such thing as "taking an array by value". Neither in C nor in C++.
This might not be the intention and might take a slice.
???
Since the array index is unsigned -1 is UB or in fact expand to UINT_MAX.
Um... My question is intended for people who have "language lawyer"
level of understanding the language. You are obviously not quite there yet.
At some point in the future you you might come across the concept colloquially known as SFINAE (which is mentioned in the subject of my question). Once you learn what it is (if ever), you will understand what this question is about.
There's no such thing as "taking an array by value". Neither in C nor
in C++.
pseudo-code sorry for any typos... Not your main point, but
#include <iostream>
struct S { static constexpr int N = -1; };
template <typename T> void foo(int [T::N])
{
std::cout << "array" << std::endl;
}
template <typename T> void foo(...)
{
std::cout << "..." << std::endl;
}
int main()
{
foo<int>(0);
}
GCC outputs "array", Clang and MSVC output "..."
The struct definition can be changed to `struct S {};` with the same
behavior from GCC. I.e. in template contexts GCC does not check the
validity of the size specified in array parameter declaration: it
doesn't care whether it is positive, it doesn't even care whether the
nested name exists. One can guess that this is most likely a
consequence of the array parameter type adjustment, which makes the
size essentially "disappear". However, it still does not necessarily
mean that such array parameter declaration should be accepted as
valid.
So, who's right here standard-wise?
You are taking an array by value. This might not be the intention and
might take a slice. Since the array index is unsigned -1 is UB or in
fact expand to UINT_MAX.
If you write
-a template <typename T> void foo(int (&)[T::N])
gcc will also output ...
I am unsure whether the overload resolution should take place
before the other checks.
First, the struct S is irrelevant; it has no bearing on the
question or the observed behavior.
Third, if we add a statement
int fred = T::N;
to the first template, gcc gives an error, whereas clang still
outputs '...'.
Fourth, if after adding 'int fred = ...' to the first template, we
change the call in main() to
foo<S>(0)
then gcc again outputs 'array', whereas clang outputs '...'.
Fifth, if after adding 'int fred = ...' to the first template, we
define a new struct
struct U { static constexpr unsigned int N = -1; };
and change the invocation in main() to
foo<U>(0)
then both gcc and clang both output 'array'.
Incidentally, trying to define an analogous pair of overloaded
functions simply rejects the definition with a negative value for
the extent of the array parameter. That holds for both gcc and
clang.
On Mon 3/2/2026 12:38 AM, Tim Rentsch wrote:
First, the struct S is irrelevant; it has no bearing on the
question or the observed behavior.
You are right. However, the `foo<int>` call in my code is a remnant of
an experiment with non-existing nested name. It also illustrates the problem.
Yet my original intent was to use
foo<S>();
call.
Third, if we add a statement
int fred = T::N;
to the first template, gcc gives an error, whereas clang still
outputs '...'.
Add where exactly? Into the body of the function template?
That would
immediately take us out of SFINAE territory and make it a hard error
in cases where `T::N` does not exist.
Not surprisingly, any compiler
that chooses the first overload will subsequently issue an error.
Fourth, if after adding 'int fred = ...' to the first template, we
change the call in main() to
foo<S>(0)
then gcc again outputs 'array', whereas clang outputs '...'.
That is another facet of the problem I mentioned in my original
question, since array declaration with negative array size is supposed
to be invalid.
Not sure what importance you assign to that "after adding..." part,
since adding 'int fred = ...' to the first template is completely
beside the point in this case.
Fifth, if after adding 'int fred = ...' to the first template, we
define a new struct
struct U { static constexpr unsigned int N = -1; };
and change the invocation in main() to
foo<U>(0)
then both gcc and clang both output 'array'.
This is expected, of course. Again, adding 'int fred = ...' to the
first template has no bearing on it.
Incidentally, trying to define an analogous pair of overloaded
functions simply rejects the definition with a negative value for
the extent of the array parameter. That holds for both gcc and
clang.
Yes, in ordinary functions, as opposed to function templates, GCC does
not ignore any issues with array sizes in parameter declarations,
which is the reason I specifically mentioned that the issue is only
visible in template context.
| Sysop: | Amessyroom |
|---|---|
| Location: | Fayetteville, NC |
| Users: | 59 |
| Nodes: | 6 (1 / 5) |
| Uptime: | 16:03:45 |
| Calls: | 810 |
| Calls today: | 1 |
| Files: | 1,287 |
| D/L today: |
10 files (21,017K bytes) |
| Messages: | 193,341 |