![](/img/trans.png)
[英]What does the C++20 standard say about usage of subojects as template non-type arguments?
[英]What does the standard say about char arrays as template arguments?
在我研究这个问题的答案时,我发现(我之前不知道)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 一起使用,我必须在全局命名空间中声明这两个字符串。 然后它也能正常工作。
所以我的问题是:标准对此有何看法? 哪个编译器(如果有)是正确的?
此问题已在 VS 2019 版本 16.4 (msvc v19.24) 中修复: https : //developercommunity.visualstudio.com/content/problem/341639/very-fragile-ice.html
这是从 C++14 到 C++17 的变化,看起来 MSVS 没有赶上。 以前在[temp.arg.nontype] 中,非类型参数必须是
非类型、非模板模板参数的模板参数应为以下之一:
对于整数或枚举类型的非类型模板参数,模板参数类型的转换常量表达式([expr.const]); 或者
非类型模板参数的名称; 或者
一个常量表达式 ([expr.const]),它指定一个完整的对象的地址,具有静态存储持续时间和外部或内部链接,或者一个具有外部或内部链接的函数,包括函数模板和函数模板 ID,但不包括非静态类成员,表示(忽略括号)为 & id-expression,其中 id-expression 是对象或函数的名称,但如果名称是指函数或数组,则可以省略 &,如果对应的名称,则应省略模板参数是一个参考; 或者
计算结果为空指针值的常量表达式 ([conv.ptr]); 或者
计算结果为空成员指针值 ([conv.mem]) 的常量表达式; 或者
一个指向成员的指针,如 [expr.unary.op] 中所述; 或者
类型为
std::nullptr_t
的常量表达式。
强调我的
并且由于第 3 条,您不能使用块作用域变量,因为块作用域变量根据[basic.link]/10没有链接
这些规则未涵盖的名称没有链接。 此外,除非另有说明,在块范围内声明的名称没有链接。
在 C++17 中,这发生了变化。 [temp.arg.nontype]现在有
非类型模板参数的模板参数应是模板参数类型的转换常量表达式。 对于引用或指针类型的非类型模板参数,常量表达式的值不得引用(或对于指针类型,不得为以下地址):
一个子对象,
一个临时对象,
字符串文字,
typeid 表达式的结果,或
预定义的 func__ 变量。
这现在允许您使用块范围静态变量
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.