正如为什么nullptr_t不是关键字所讨论的那样,最好避免引入新关键字,因为它们可能会破坏向后兼容性.
为什么然后是char16_t和char32_t关键词,当他们可以这样定义?
namespace std {
typedef decltype(u'q') char16_t;
typedef decltype(U'q') char32_t;
}
Run Code Online (Sandbox Code Playgroud) GCC和Clang都拒绝接受以下代码中的C风格演员.
http://coliru.stacked-crooked.com/a/c6fb8797d9d96a27
struct S {
typedef const int* P;
operator P() { return nullptr; }
};
int main() {
int* p1 = const_cast<int*>(static_cast<const int*>(S{}));
int* p2 = (int*)(S{});
}
Run Code Online (Sandbox Code Playgroud)
main.cpp: In function 'int main()':
main.cpp:7:25: error: invalid cast from type 'S' to type 'int*'
int* p2 = (int*)(S{});
main.cpp:7:15: error: cannot cast from type 'S' to pointer type 'int *'
int* p2 = (int*)(S{});
^~~~~~~~~~~
但是,根据标准,C风格的演员表可以执行a static_cast后跟a 执行的转换const_cast.这段代码是否格式良好?如果没有,为什么不呢?
该问题是针对以下问题的后续措施:当它实际上未指向char数组时,是否将其添加到“ char *”指针UB?
在CWG 1314中,CWG确认使用指针在标准布局对象中执行指针算术是合法的unsigned char。这似乎意味着与链接的问题类似的某些代码应按预期工作:
struct Foo {
float x, y, z;
};
Foo f;
unsigned char *p = reinterpret_cast<unsigned char*>(&f) + offsetof(Foo, z); // (*)
*reinterpret_cast<float*>(p) = 42.0f;
Run Code Online (Sandbox Code Playgroud)
(为了更清楚起见,我用替换char了unsigned char。)
但是,似乎C ++ 17中的新更改意味着该代码现在是UB,除非std::launder在两个reinterpret_casts 之后都使用。reinterpret_cast两种指针类型之间的a结果等于两个static_casts:第一个为cv void*,第二个为目标指针类型。但是[expr.static.cast] / 13暗示这会生成指向原始对象的指针,而不是指向目标类型的对象的Foo指针,因为类型的对象不能与unsigned char对象的第一个字节进行指针互换,也不是一个unsigned char对象在的第一个字节f.z指针相互转换与f.z本身。
我很难相信委员会打算进行更改以打破这种非常普遍的习惯用法,从而使C ++ 17之前的所有用法都不offsetof确定。
根据[expr.cast]/4,C风格的强制转换按顺序尝试以下强制转换:
const_caststatic_caststatic_cast 其次是 const_castreinterpret_castreinterpret_cast 其次是 const_cast以下演员表格很好:
const_cast<int&>(static_cast<const int&>(0))
Run Code Online (Sandbox Code Playgroud)
然而,GCC和Clang都拒绝演员(int&)0.为什么?
例如,着名的单词(§3.2/ 1)
任何翻译单元都不得包含任何变量,函数,类类型,枚举类型或模板的多个定义.
除非另有说明,否则我认为"必须"的要求应被解释为"除非程序形成不良".然而,其他人则声称"应"代表"否则行为未定义".
在每种情况下,我都会遇到标准,其中"必须"要求后面没有"行为未定义"或"无需诊断"之类的内容,其中发生的规则显然是可以诊断的规则.由我所知的所有编译器诊断出来(以上段落就是一个例子).这就是为什么我认为这意味着"否则程序形成不良",即需要诊断.
无论如何,那些只是我的想法.我很欣赏一个权威的答案.
我在不同的地方看过N3690,N4140和N4296.我猜它是N4140,因为它是在2014年底发布的.N4296似乎有不像C++ 14那样的东西,就像折叠表达式一样.
在C ++ 20中,不赞成使用POD的概念,因为它是琐碎且标准的布局的无意义的合成特征。但是,C ++ 20草案中的POD定义并不完全是“琐碎的和标准布局”;实际上是:
POD类是既是普通类又是标准布局类的类,并且不具有非POD类类型的非静态数据成员(或其数组)。POD类型是标量类型,POD类,这种类型的数组或这些类型之一的cv限定版本。
换句话说,POD类型不仅是琐碎的而且是标准布局的,而且也是递归的。
该递归需求是否多余?换句话说,如果一个类型既是琐碎的又是标准布局,那么它是否也自动递归地变得琐碎又是标准布局?如果答案为“否”,那么标准布局,琐碎类型却不能成为POD的例子是什么?
更具体地讲,假设我写template<class Pointer> class Foo,我要声明一个typedef类里面的那个类型*p,如果必须p是类型Pointer.
在C++ 03中,据我所知,唯一的方法是使用类似的东西
typename std::iterator_traits<Pointer>::reference
Run Code Online (Sandbox Code Playgroud)
这种方法的缺点是,如果Pointer是一些自定义迭代器类型并且作者忘记扩展std::iterator或以其他方式定义特化,它将不起作用std::iterator_traits.
在C++ 11中,我的同事建议
decltype(*Pointer())
Run Code Online (Sandbox Code Playgroud)
但是如果Pointer不是默认构造的话,这将不起作用,所以他将其修改为
decltype(**(Pointer*)0)
Run Code Online (Sandbox Code Playgroud)
我尝试了这个,但它确实有效,但后来我认为它看起来有点不确定因为它涉及空引用的解引用,因此可能不符合标准.
我们可以做得更好吗?
例如,这无法编译:
std::function<decltype(printf)> my_printf(printf);
使用gcc,错误消息显示为:
error: variable 'std::function<int(const char*, ...)> my_printf' has initializer but incomplete type
std::function<decltype(printf)> my_printf(printf);
Run Code Online (Sandbox Code Playgroud)
起初我以为这是gcc中的一个错误,但后来我看了标准,看起来这样就不支持了.这是什么技术原因?
根据C ++ 17 [basic.compound] / 3:
指针类型的每个值都是以下之一:
- 指向对象或函数的指针(据说该指针指向对象或函数),或
- 一个超出对象末尾的指针(8.7),或者
- 该类型的空指针值(7.11),或者
- 无效的指针值。
该malloc函数返回一个指针值。让我们假设调用成功,因此返回值不为null。malloc([c.malloc])的规范没有声明它在返回的存储中创建了任何对象,因此似乎“无效的指针值”是最没有意义的类别。