c++ - 标准对 char 数组作为模板参数有什么看法?

标签 c++ templates language-lawyer c++17 linkage

在研究 this question 的答案期间我发现(我之前不知道)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]非类型参数必须是

A template-argument for a non-type, non-template template-parameter shall be one of:

  • for a non-type template-parameter of integral or enumeration type, a converted constant expression ([expr.const]) of the type of the template-parameter; or

  • the name of a non-type template-parameter; or

  • a constant expression ([expr.const]) that designates the address of a complete object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as & id-expression, where the id-expression is the name of an object or function, except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; or

  • a constant expression that evaluates to a null pointer value ([conv.ptr]); or

  • a constant expression that evaluates to a null member pointer value ([conv.mem]); or

  • a pointer to member expressed as described in [expr.unary.op]; or

  • a constant expression of type std::nullptr_t.

强调我的

并且由于第 3 条,您不能使用 block 作用域变量,因为 block 作用域变量根据 [basic.link]/10 没有链接。

Names not covered by these rules have no linkage. Moreover, except as noted, a name declared at block scope has no linkage.

在 C++17 中,这发生了变化。 [temp.arg.nontype]现在有

A template-argument for a non-type template-parameter shall be a converted constant expression of the type of the template-parameter. For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):

  • a subobject,

  • a temporary object,

  • a string literal,

  • the result of a typeid expression, or

  • a predefined ­­func_­_­ variable.

这现在允许您使用 block 范围静态变量

关于c++ - 标准对 char 数组作为模板参数有什么看法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57009060/

相关文章:

c++ - 为什么不能重载三元运算符?

c++ - 为什么将 wcout/wcerr 重定向到/dev/null 会导致程序崩溃?

c++ - 关于不完整类型的 SFINAE 的特殊规则

c++ - 是否对未指向序列未定义行为中的元素的指针递增/递减或添加整数值?

c++ - 如何检测 Qt 中的用户不活动?

c++ - 如何使用可变模板参数保存可变数量的参数?

c++ - 使用模板参数包解析一行文本

c++ - 如何验证某些模板是否*不*针对给定的参数类型进行编译?

c - 只要您永远不取消引用它,持有未对齐的指针是否定义明确?

c++ - C++17 中不可复制变量的成员初始化