【问题标题】:constexpr int* ptr =&i compiles in msvc but not with clang and gccconstexpr int* ptr =&i 在 msvc 中编译,但不使用 clang 和 gcc
【发布时间】:2022-10-18 22:38:30
【问题描述】:

我正在使用here 列出的书籍了解constexpr 变量。特别是我在 C++ Primer 中读到:

声明为 constexpr 的变量是隐式 const 并且必须使用常量表达式进行初始化。

现在,为了进一步理清我的概念并检查我是否理解正确,我编写了以下简单的程序,该程序使用 msvc 但不使用 gcc 和 clang 编译: Demo

int main(void)
{
   int i = 0;
   constexpr int *ptr= &i; //compiles with msvc but not with clang and gcc 
}

所以,我的问题是哪个编译器在这里(如果有的话)?

【问题讨论】:

标签: c++ pointers reference language-lawyer constexpr


【解决方案1】:

该程序是格式不正确msvc 接受代码错误.这是因为i 不是静态分配的对象,所以它的地址不是常数。基本上,因为我们只能从 nullptr 文字或文字 0从具有固定地址的对象的地址在您的示例中,i 不是具有固定地址的对象,因此&i不是常量表达式.

这可以从expr.const#11 中看出,其中指出:

常量表达式要么是glvalue 核心常量表达式,它引用作为常量表达式(如下定义)的允许结果的实体,或prvalue 核心常量表达式,其值满足以下约束

  • 如果该值是指针类型,则它包含具有静态存储持续时间的对象的地址,此类对象末尾的地址([expr.add]),非立即函数的地址或空指针值,

如果实体是具有静态存储持续时间的对象,该对象不是临时对象或者是其值满足上述约束的临时对象,或者它是非立即函数,则该实体是常量表达式的允许结果。

(强调我的)

这意味着有两种方法可以解决问题。第一的是您可以在i 前面添加static 以使其成为本地静态。这第二就是将i的定义移到主函数之外的全局作用域。在这两种情况下(如下所示),i 将拥有静态存储时间这样&i 现在将根据上面引用的语句成为一个常量表达式。


方法一

int main()
{
//-vvvvvv------------->static added here so that i now has static storage duration
   static int i = 0;
   constexpr int *ptr= &i; //works now
   
}

方法二

int i = 0;  //make i global so that i now has static storage duration  
int main()
{

   constexpr int *ptr= &i; //works now   
}

这是 msvc 错误报告:

MSVC compiles invalid constexpr int*ptr= &i where i is a local nonstatic object

【讨论】:

  • 在报告新的 msvc 错误之前,应通过使用标志 /permissive- 进行编译来确认。
  • 是的,这不是编译器错误,而是扩展,错误报告可能会被关闭。
  • @273K 该程序不使用/permissive- 进行诊断。 Demo。所以,这似乎是一个错误。
  • @273K 即使使用您建议的标志,我们也没有得到任何诊断。所以这看起来像这个答案中所说的错误。
  • 这是一个有趣的案例,因为main 不是通常的函数。它不能被另一个函数调用,副作用是本地对象的地址永远不会不同。仍然,一个技术错误。
猜你喜欢
  • 2020-06-03
  • 2017-10-12
  • 2018-08-02
  • 2022-10-12
  • 2023-03-21
  • 1970-01-01
  • 2017-10-17
  • 2023-03-23
  • 1970-01-01
相关资源
最近更新 更多