繁体   English   中英

标准对作为模板参数的 char 数组有何看法?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM