- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
考虑以下代码:
struct foo {
static constexpr const void* ptr = reinterpret_cast<const void*>(0x1);
};
auto main() -> int {
return 0;
}
上面的例子在 g++ v4.9 ( Live Demo ) 中编译良好,而在 clang v3.4 ( Live Demo ) 中编译失败并产生以下错误:
error: constexpr variable 'ptr' must be initialized by a constant expression
问题:
根据标准,这两个编译器哪个是正确的?
声明此类表达式的正确方法是什么?
最佳答案
TL;DR
clang
是正确的,这是已知的 gcc
错误。您可以改用 intptr_t
并在需要使用该值时进行强制转换,或者如果这不可行,则 gcc
和 clang
都支持一点记录在案的解决方法应该允许您的特定用例。
详情
所以如果我们转到 draft C++11 standard,clang
是正确的。 5.19
常量表达式 小节 2 说:
A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression [...]
并包括以下项目符号:
— 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] Constant expressions support reinterpret_cast .从讨论中可以清楚地看出,gcc
开发人员对此有一些明确的用例:
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.
但无法为这些用例生成异常,请参阅 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 显然 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 is informative以下片段提供了一些有趣的阅读:
support the gcc __builtin_constant_p() ? ... : ... folding hack in C++11
和:
// __builtin_constant_p ? : is magical, and is always a potential constant.
和:
// 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))
我们可以在 gcc-patches 电子邮件中找到对此功能更正式的解释:C constant expressions, VLAs etc. fixes其中说:
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.
关于c++ - constexpr 和使用重新解释强制转换的静态 const void 指针的初始化,哪个编译器是正确的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24398102/
我刚接触 C 语言几周,所以对它还很陌生。 我见过这样的事情 * (variable-name) = -* (variable-name) 在讲义中,但它到底会做什么?它会否定所指向的值吗? 最佳答案
我有一个指向内存地址的void 指针。然后,我做 int 指针 = void 指针 float 指针 = void 指针 然后,取消引用它们以获取值。 { int x = 25; vo
我正在与计算机控制的泵进行一些串行端口通信,我用来通信的 createfile 函数需要将 com 端口名称解析为 wchar_t 指针。 我也在使用 QT 创建一个表单并获取 com 端口名称作为
#include "stdio.h" #include "malloc.h" int main() { char*x=(char*)malloc(1024); *(x+2)=3; --
#include #include main() { int an_int; void *void_pointer = &an_int; double *double_ptr = void
对于每个时间步长,我都有一个二维矩阵 a[ix][iz],ix 从 0 到 nx-1 和 iz 从 0 到 nz-1。 为了组装所有时间步长的矩阵,我定义了一个长度为 nx*nz*nt 的 3D 指针
我有一个函数,它接受一个指向 char ** 的指针并用字符串填充它(我猜是一个字符串数组)。 *list_of_strings* 在函数内部分配内存。 char * *list_of_strings
我试图了解当涉及到字符和字符串时,内存分配是如何工作的。 我知道声明的数组的名称就像指向数组第一个元素的指针,但该数组将驻留在内存的堆栈中。 另一方面,当我们想要使用内存堆时,我们使用 malloc,
我有一个 C 语言的 .DLL 文件。该 DLL 中所有函数所需的主要结构具有以下形式。 typedef struct { char *snsAccessID; char *
指针, C语言的精髓 莫队先咕几天, 容我先讲完树剖 (因为后面树上的东西好多都要用树剖求 LCA). 什么是指针 保存变量地址的变量叫做指针. 这是大概的定义, 但是Defad认为
我得到了以下数组: let arr = [ { children: [ { children: [], current: tru
#include int main(void) { int i; int *ptr = (int *) malloc(5 * sizeof(int)); for (i=0;
我正在编写一个程序,它接受一个三位数整数并将其分成两个整数。 224 将变为 220 和 4。 114 将变为 110 和 4。 基本上,您可以使用模数来完成。我写了我认为应该工作的东西,编译器一直说
好吧,我对 C++ 很陌生,我确定这个问题已经在某个地方得到了回答,而且也很简单,但我似乎找不到答案.... 我有一个自定义数组类,我将其用作练习来尝试了解其工作原理,其定义如下: 标题: class
1) this 指针与其他指针有何不同?据我了解,指针指向堆中的内存。如果有指向它们的指针,这是否意味着对象总是在堆中构造? 2)我们可以在 move 构造函数或 move 赋值中窃取this指针吗?
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: C : pointer to struct in the struct definition 在我的初学者类
我有两个指向指针的结构指针 typedef struct Square { ... ... }Square; Square **s1; //Representing 2D array of say,
变量在内存中是如何定位的?我有这个代码 int w=1; int x=1; int y=1; int z=1; int main(int argc, char** argv) { printf
#include #include main() { char *q[]={"black","white","red"}; printf("%s",*q+3); getch()
我在“C”类中有以下函数 class C { template void Func1(int x); template void Func2(int x); }; template void
我是一名优秀的程序员,十分优秀!