constexpr和初始化一个静态const void指针与reinterpret转换,这是什么编译器是正确的? [英] constexpr and initialization of a static const void pointer with reinterpret cast, which compiler is right?

查看:153
本文介绍了constexpr和初始化一个静态const void指针与reinterpret转换,这是什么编译器是正确的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑下面的代码:

  struct foo {
static constexpr const void * ptr = reinterpret_cast< const void *>(0x1);
};

auto main() - > int {
return 0;上面的例子在g ++ v4.9()中编译正确, http://coliru.stacked-crooked.com/a/90c872d2d3572488\">实例演示),但无法在clang v3.4(现场演示)并生成以下错误:


错误:constexpr变量'ptr'必须由常量表达式初始化


问题:


  • 根据标准,哪两个编译器是正确的?




解决方案

TL; DR



clang 是正确的,这是已知的 gcc 错误。你可以使用 intptr_t 而不是当你需要使用值或者如果这是不可行的然后两个 gcc clang 支持一些文档化的工作,应该允许您的特定用例。



详细信息



所以 clang 在这一个上是正确的,如果我们去草案C ++ 11标准部分 5.19 段落 说:


条件表达式是一个核心常量表达式,除非
涉及以下之一作为潜在求值的子表达式
[...]


并包含以下项目:


- a reinterpret_cast(5.2.10);


一个简单的解决方案是使用 intptr_t

  static constexpr intptr_t ptr = 0x1; 

,然后在需要使用时进行投放:

  reinterpret_cast< void *>(foo :: ptr); 

这可能是诱人的,但这个故事更有趣。这是已知且仍然开放的 gcc 错误,请参阅 Bug 49171:[C ++ 0x] [constexpr]常量表达式支持reinterpret_cast 。从讨论中清楚的是, gcc devs有一些明确的用例:


我相信我发现reinterpret_cast在常量
表达式中可用于C ++ 03中的符合使用:

  / ---------------- struct X {X * operator&(); }; 

X x [2];

const bool p =(reinterpret_cast< X *>(& reinterpret_cast< char&>(x [1]))
- reinterpret_cast< X *>(& reinterpret_cast< ; char&>(x [0])))== sizeof(X);

枚举E {e = p}; // e应该有一个等于1的值
// ----------------

基本上这个程序演示了这个技术,C ++ 11库
函数addressof基于,因此排除了reinterpret_cast
无条件核心语言中的常量表达式会使这个有用的程序无效,并且不可能将
声明为一个constexpr函数的addressof。


但无法获取针对这些用例的异常,请参阅关闭的问题1384


虽然reinterpret_cast允许在地址常量
中的表达式在C + 03,这个限制已经在一些
编译器中实现,并且没有证明打破了大量的代码。 CWG
认为处理其tpes
改变的指针的并发症(指针运算和取消引用不能在
这样的指针上被允许)超过放松当前
限制的可能效用。


显然 gcc clang 支持一个有点文件化的扩展,它允许使用 __ builtin_constant_p(exp),所以下面的表达式被 gcc clang

  static constexpr const void * ptr = 
__builtin_constant_p(reinterpret_cast< const void *> 0x1))?
reinterpret_cast< const void *>(0x1):reinterpret_cast< const void *>(0x1);

查找文档几乎不可能,但这 llvm commit是信息性的,以下片段提供了一些有趣的阅读:



  • 支持gcc __builtin_constant_p()? ...:...在C ++ 11中折叠hack


>


+ // __builtin_constant_p? :是神奇的,总是潜在的常数。


和:



< >

  • //此宏强制其参数为常数折叠,即使它不是

  • //否则为常量表达式。

  • define fold(x)(__builtin_constant_p(x)?(x):(x))



我们可以在gcc-patches电子邮件中找到这个功能的更正式的解释: C常量表达式,VLA等修复,它说:


此外,__builtin_constant_p的规则调用作为条件
表达式条件在实现中比那些
在正式模型中更轻松:选择的一半条件表达式
因为__builtin_constant_p测试一个完全折叠的参数
本身。



表示完全折叠,而不考虑它是否是一个常量
表达式

Consider the following piece of code:

struct foo {
  static constexpr const void* ptr = reinterpret_cast<const void*>(0x1);
};

auto main() -> int {
  return 0;
}

The above example compiles fine in g++ v4.9 (Live Demo), while it fails to compile in clang v3.4 (Live Demo) and generates the following error:

error: constexpr variable 'ptr' must be initialized by a constant expression

Questions:

  • Which of the two compilers is right according to the standard?

  • What's the proper way of declaring an expression of such kind?

解决方案

TL;DR

clang is correct, this is known gcc bug. You can either use intptr_t instead and cast when you need to use the value or if that is not workable then both gcc and clang support a little documented work-around that should allow your particular use case.

Details

So clang is correct on this one if we go to the draft C++11 standard section 5.19 Constant expressions paragraph 2 says:

A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression [...]

and includes the following bullet:

— a reinterpret_cast (5.2.10);

One simple solution would be to use intptr_t:

static constexpr intptr_t ptr = 0x1;

and then cast later on when you need to use it:

reinterpret_cast<void*>(foo::ptr) ;

It may be tempting to leave it at that but this story gets more interesting though. This is know and still open gcc bug see Bug 49171: [C++0x][constexpr] Constant expressions support reinterpret_cast. It is clear from the discussion that gcc devs have some clear use cases for this:

I believe I found a conforming usage of reinterpret_cast in constant expressions useable in C++03:

//---------------- struct X {  X* operator&(); };

X x[2];

const bool p = (reinterpret_cast<X*>(&reinterpret_cast<char&>(x[1]))
- reinterpret_cast<X*>(&reinterpret_cast<char&>(x[0]))) == sizeof(X);

enum E { e = p }; // e should have a value equal to 1
//----------------

Basically this program demonstrates the technique, the C++11 library function addressof is based on and thus excluding reinterpret_cast unconditionally from constant expressions in the core language would render this useful program invalid and would make it impossible to declare addressof as a constexpr function.

but were not able to get an exception carved for these use cases, see closed issues 1384:

Although reinterpret_cast was permitted in address constant expressions in C++03, this restriction has been implemented in some compilers and has not proved to break significant amounts of code. CWG deemed that the complications of dealing with pointers whose tpes changed (pointer arithmetic and dereference could not be permitted on such pointers) outweighed the possible utility of relaxing the current restriction.

BUT apparently gcc and clang support a little documented extension that allows constant folding of non-constant expressions using __builtin_constant_p (exp) and so the following expressions is accepted by both gcc and clang:

static constexpr const void* ptr = 
  __builtin_constant_p( reinterpret_cast<const void*>(0x1) ) ? 
    reinterpret_cast<const void*>(0x1) : reinterpret_cast<const void*>(0x1)  ;

Finding documentation for this is near impossible but this llvm commit is informative with the following snippets provide for some interesting reading:

  • support the gcc __builtin_constant_p() ? ... : ... folding hack in C++11

and:

+// __builtin_constant_p ? : is magical, and is always a potential constant.

and:

  • // This macro forces its argument to be constant-folded, even if it's not
  • // otherwise a constant expression.
  • define fold(x) (__builtin_constant_p(x) ? (x) : (x))

We can find a more formal explanation of this feature in the gcc-patches email: C constant expressions, VLAs etc. fixes which says:

Furthermore, the rules for __builtin_constant_p calls as conditional expression condition in the implementation are more relaxed than those in the formal model: the selected half of the conditional expression is fully folded without regard to whether it is formally a constant expression, since __builtin_constant_p tests a fully folded argument itself.

这篇关于constexpr和初始化一个静态const void指针与reinterpret转换,这是什么编译器是正确的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆