【问题标题】:Is address of global variable constexpr?是全局变量 constexpr 的地址吗?
【发布时间】:2016-12-11 10:29:56
【问题描述】:

考虑关注

struct dummy{};

dummy d1;
dummy d2;

template<dummy* dum>
void foo()
{
    if (dum == &d1)
        ; // do something
    else if (dum == &d2)
        ; // do something else
}

现在,可以像这样调用foo

foo<&d1>();
foo<&d2>();

一切都按预期进行。但以下没有

constexpr dummy* dum_ptr = &d1;
foo<dum_ptr>();

Visual Studio 出现此错误

错误 C2975:dum_ptrfoo 的模板参数无效,预期的编译时常量表达式

虽然这有效

constexpr dummy& dum_ref = d1;
foo<&dum_ptr>();

在 Visual Studio 中,但不在 G++ 中,因为

注意:模板参数扣除/替换失败:
错误:&amp; dum_ref 不是 dummy* 的有效模板参数,因为它不是变量的地址

foo<&dum_ref>();

编辑:
由于 C++17,std::addressof 被标记为 constexpr,所以我猜它应该可以工作。

【问题讨论】:

  • foo&lt;dum_ptr&gt;(); 在 g++ 中也不起作用。
  • 有趣。我用-std=c++1z 试过了,它可以工作,但你是对的。它不适用于-std=c++14
  • 模板中可能是dummy const * dumdummy constexpr * dum
  • 我很惊讶。它如何与位置无关代码(PIC)、全局偏移表(GOT)和过程链接表(PLT)一起工作?这些地址不是有时只能在运行时定义吗?这个 constexpr 地址有什么魔力?

标签: c++11 language-lawyer


【解决方案1】:

GCC 是正确的。

表达式肯定是constant-expressions*,因为它们被分配给constexpr 变量。但是,在 c++14 之前,指针模板参数允许的内容有额外的限制。

C++14 草案 N4140 [temp.arg.nontype]

1 非类型、非模板模板参数的模板参数应为以下之一:

  • 对于整数或枚举类型的非类型模板参数,转换后的常量表达式 (5.19) 的类型 模板参数;或
  • 非类型模板参数的名称;或
  • 一个常量表达式 (5.19),它指定具有静态存储持续时间和外部或内部的完整对象的地址 链接或与外部或内部链接的功能,包括 函数模板和函数模板 ID,但不包括非静态 类成员,表示(忽略括号)为 &amp;id-expression,其中 id-expression 是对象的名称 或 函数,除了如果名称指的是一个 & 可以省略 函数或数组,如果对应的则应省略 模板参数是一个参考;或
  • 计算结果为空指针值的常量表达式 (4.10);要么 一个常量表达式,计算结果为空成员指针值 (4.11);要么 指向成员的指针,如 5.3.1 所述;要么 std::nullptr_t 类型的常量表达式。

对于foo&lt;dum_ptr&gt;()dum_ptr 不表示为&amp;name,对于foo&lt;&amp;dum_ref&gt;()dum_ref 不是对象的名称,而是对象引用的名称,所以两者不允许作为模板参数。

这些限制在 c++17 中被取消以允许任何 constexpr,这就是它在那里工作的原因:

C++17 草案 N4606 - 14.3.2 模板非类型参数 [temp.arg.nontype]

1 非类型模板参数的模板参数应为 类型的转换常量表达式 (5.20) 模板参数。对于参考的非类型模板参数或 指针类型,常量表达式的值不得引用 (或者对于指针类型,不得是地址):

  • (1.1) 子对象 (1.8),
  • (1.2) 临时对象 (12.2),
  • (1.3) 字符串字面量 (2.13.5),
  • (1.4) typeid 表达式 (5.2.8) 的结果,或
  • (1.5) 一个预定义的 __func__ 变量 (8.4.1)。

像往常一样,clang 给出了最好的错误信息: https://godbolt.org/g/j0Q2bV


*(参见地址常量表达式引用常量表达式

【讨论】:

    猜你喜欢
    • 2019-09-06
    • 2021-09-14
    • 1970-01-01
    • 2020-06-22
    • 1970-01-01
    • 2019-06-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-26
    相关资源
    最近更新 更多