During my research for an answer for this question I found (I did not know that before) that gcc and clang allow char
arrays to be template arguments if they are declared static
. E.g. this code compiles with gcc and clang:
#include <type_traits>
template <int N, const char (&string)[N]>
auto foo()
{
if constexpr (string[0] == 'i')
return 0;
else
return 3.14f;
}
void bar()
{
static constexpr char string1[] = "int";
static constexpr char string2[] = "float";
auto i = foo<sizeof(string1), string1>();
auto f = foo<sizeof(string2), string2>();
static_assert(std::is_same_v<decltype(i), int>);
static_assert(std::is_same_v<decltype(f), float>);
}
MSVC also allows that. However, to make it work with MSVC, I have to declare the two strings in the global namespace. Then it works just as well.
So my question is: What does the standard say about this? Which compiler (if any) is right?
Update:
This issue has been fixed in VS 2019 version 16.4 (msvc v19.24): https://developercommunity.visualstudio.com/content/problem/341639/very-fragile-ice.html
This is a change from C++14 to C++17 that looks like MSVS hasn't caught up with. Previously in [temp.arg.nontype] a non type argument had to be
emphasis mine
and because of bullet 3 you could not use a block scope variable as block scope variables have no linkage per [basic.link]/10
In C++17 this changes. [temp.arg.nontype] now has
This now allows you to use a block scope static variable