在我研究答案的过程中这个问题 https://stackoverflow.com/q/57003010/9883438我发现(我之前不知道)gcc 和 clang 允许char
如果声明了数组,则它们将成为模板参数static
。例如。此代码使用 gcc 和 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 也允许这样做。但是,为了使其与 MSVC 一起工作,我必须在全局命名空间中声明这两个字符串。那么它也同样有效。
所以我的问题是:标准对此有何规定?哪个编译器(如果有)是正确的?
Update:
此问题已在 VS 2019 版本 16.4 (msvc v19.24) 中修复:https://developercommunity.visualstudio.com/content/problem/341639/very-fragile-ice.html https://developercommunity.visualstudio.com/content/problem/341639/very-fragile-ice.html
这是从 C++14 到 C++17 的变化,看起来 MSVS 还没有跟上。以前在[temp.arg.nontype] https://timsong-cpp.github.io/cppwp/n4140/temp.arg.nontype非类型参数必须是
非类型、非模板模板参数的模板参数应为以下之一:
对于整型或枚举类型的非类型模板参数,模板参数类型的转换常量表达式([expr.const]);或者
非类型模板参数的名称;或者
常量表达式 ([expr.const]),指定具有静态存储持续时间和外部或内部链接的完整对象的地址或具有外部或内部链接的函数,包括函数模板和函数模板 ID,但不包括非静态类成员,表示(忽略括号)为 & id-表达式,其中 id-表达式 是对象或函数的名称,但如果名称引用函数或数组,则可以省略 &;如果相应的模板参数是引用,则应省略 &;或者
计算结果为空指针值的常量表达式 ([conv.ptr]);或者
计算结果为空成员指针值的常量表达式 ([conv.mem]);或者
指向成员的指针,如 [expr.unary.op] 中所述表达;或者
类型的常量表达式std::nullptr_t
.
emphasis mine
由于第 3 点,您无法使用块作用域变量,因为块作用域变量没有链接[基本.链接]/10 https://timsong-cpp.github.io/cppwp/basic.link#10
这些规则未涵盖的名称没有任何联系。此外,除非另有说明,在块作用域中声明的名称没有链接。
在 C++17 中,情况发生了变化。[temp.arg.nontype] https://timsong-cpp.github.io/cppwp/n4659/temp.arg.nontype now has
非类型模板参数的模板参数应是模板参数类型的转换后的常量表达式。对于引用或指针类型的非类型模板参数,常量表达式的值不应引用(或对于指针类型,不应是以下地址):
一个子对象,
一个临时的物体,
字符串文字,
typeid 表达式的结果,或
一个预定义的func__ 变量。
现在允许您使用块作用域静态变量
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)