Questions tagged «language-lawyer»

有关编程语言和环境的正式或权威规范的复杂性的问题。

2
零长度数组的指针的属性
考虑 int main() { auto a = new int[0]; delete[] a; // So there's no memory leak } 在复制初始化和删除之间,是否允许您读取处的指针a + 1? 此外,该语言是否允许编译器设置a为nullptr?

4
不允许隐式转换返回
#include <optional> bool f() { std::optional<int> opt; return opt; } 无法编译: 'return': cannot convert from 'std::optional<int>' to 'bool' 咨询参考本来可以找到解释的,但我读了应该可以。 每当在上下文中使用某种类型T1的表达式但不接受该类型但接受某种其他类型的T2时,都会执行隐式转换。特别是: 当调用以T2作为参数声明的函数时,将表达式用作参数时; 当表达式用作期望T2的运算符的操作数时; 初始化类型为T2的新对象时,包括返回T2的函数中的return语句; 当在switch语句中使用该表达式时(T2是整数类型); 在if语句或循环中使用该表达式时(T2为bool)。

1
为什么{}作为函数参数不会导致歧义?
考虑以下代码: #include <vector> #include <iostream> enum class A { X, Y }; struct Test { Test(const std::vector<double>&, const std::vector<int>& = {}, A = A::X) { std::cout << "vector overload" << std::endl; } Test(const std::vector<double>&, int, A = A::X) { std::cout << "int overload" << std::endl; } }; int main() { …

4
将std :: transform与std :: back_inserter一起使用是否有效?
Cppreference具有以下示例代码std::transform: std::vector<std::size_t> ordinals; std::transform(s.begin(), s.end(), std::back_inserter(ordinals), [](unsigned char c) -> std::size_t { return c; }); 但这也说: std::transform不保证unary_op或的顺序应用binary_op。要将功能按顺序应用于序列或将功能修改序列的元素,请使用std::for_each。 大概是为了允许并行实现。但是,第三个参数std::transform是a LegacyOutputIterator,它具有以下条件++r: 此操作之后,r不需要是可递增的,并且r不再需要先前值的任何副本是可取消引用或可递增的。 因此在我看来,输出的分配必须按顺序进行。它们是否仅表示的应用程序unary_op可能会乱序,并存储到一个临时位置,但按顺序复制到输出中?这听起来不像您想做的事情。 大多数C ++库实际上尚未实现并行执行程序,但Microsoft已实现。我很确定这是相关的代码,并且我认为它调用此populate()函数来将迭代器记录到输出的大块中,这肯定不是一件有效的事情,因为 LegacyOutputIterator可以通过递增其副本来使其无效。 我想念什么?


2
箭头(->)运算符的优先级/优先级最低,还是分配/组合分配的优先级最低?
JLS: 的最低优先级操作者是lambda表达式的箭头( - >) ,接着由赋值运算符。 遵循哪个方向(增加优先级,减少优先级)?-“跟随”是指分配的优先级较高还是较低(相对于箭头运算符)?我猜想,这是因为“最低”(箭头)表示绝对最低。 据我了解,箭头(->)应该在此普林斯顿的最底部运算符优先级表的(位于所有赋值运算符的下方),因此箭头(->)的优先级为0(零)(根据该表)。 我的理解正确吗? 考试托盘似乎说箭头优先级至少与分配相同。此外,还阐明了箭头的关联性是Left-> To-> Right(与分配不同)。我没有找到JLS的箭头关联性报价。 我一直认为分配优先级原则上最低。

2
跳过变量初始化格式错误还是会导致不确定的行为?
考虑以下代码: void foo() { goto bar; int x = 0; bar: ; } GCC和Clang 拒绝了它,因为跳转到bar:绕过了变量初始化。MSVC一点也不抱怨(使用x after bar:会引起警告)。 我们可以使用来做类似的事情switch: void foo() { switch (0) { int x = 0; case 0: ; } } 现在所有三个编译器 发出错误。 这些代码片段格式不正确吗?还是引起UB? 我曾经以为两者都是不正确的形式,但是我找不到标准的启示部分。[stmt.goto]不说这事,而且也不[stmt.select] 。

1
为什么C ++标准会处理文件查找方式?
C ++使用该streamoff类型表示(文件)流中的偏移量,并在[stream.types]中定义如下: using streamoff = implementation-defined ; 类型streamoff是已签名的基本整数类型之一的同义词,该基本整数类型的大小足以表示操作系统的最大可能文件大小。287) 287)通常很长很长。 这是有道理的,因为它允许在大型文件中进行查找(与使用相比long,后者可能只有32位宽)。 [filebuf.virtuals]定义了basic_filebuf在文件中进行搜索的功能,如下所示: pos_type seekoff(off_type off, ios_base::seekdir way, ios_base::openmode which = ios_base::in | ios_base::out) override; off_type等价于streamoff,请参见[iostreams.limits.pos]。但是,该标准随后继续说明了该功能的作用。最后一句话让我很生气,这需要调用fseek: 效果:width表示a_codecvt.encoding()。如果is_open() == false是或off != 0 && width <= 0,则定位操作将失败。否则,如果way != basic_ios::cur或off != 0,并且输出了最后一个操作,则更新输出序列并写入所有未移位序列。接下来,寻找新的位置:if width > 0,请致电fseek(file, width * off, whence),否则请致电fseek(file, 0, whence)。 fseek接受long参数。如果off_type和streamoff被定义为long long(如标准所建议),则可能导致向下转换为long调用时fseek(file, width * …

1
Clang是否正确拒绝仅通过专门化定义类模板的嵌套类的代码?
给定以下类模板: template<typename T> struct Outer { struct Inner; auto f(Inner) -> void; }; 我们Inner为以下每种专业分别定义Outer: template<> struct Outer<int>::Inner {}; template<> struct Outer<double>::Inner {}; 然后f针对以下所有专业定义一次成员函数Outer: auto Outer<T>::f(Inner) -> void { } 但是Clang(9.0.0)抱怨: error: variable has incomplete type 'Outer::Inner' auto Outer<T>::f(Inner) -> void ^ 我们还可以通过提供Inner以下所有其他专长的定义来规避编译器错误Outer: template<typename T> struct Outer<T>::Inner {}; 或通过f为每个专业分别定义: template<> auto …

1
sizeof(enum)是否可以与sizeof(std :: underlying_type <Enum> :: type)不同?
最近出现在以下示例中的代码审查中: enum class A : uint8_t { VAL1, VAL2 }; ... std::vector&lt;A&gt; vOfA; // Assume this is sized and full of some stuff. std::memcpy(wire_buffer, vOfA.data(), vOfA.size() * sizeof(A)); 我们应该使用sizeof(std::underlying_type&lt;A&gt;::type)而不是sizeof(A)。这些可能会有所不同吗?有人提供标准报价来保证这一点吗?

1
Haskell解析器是否应该允许数字文字使用Unicode数字?
作为练习,我将从头开始为Haskell编写解析器。在编写词法分析器时,我注意到Haskell 2010报告中的以下规则: 数 → ascDigit | uniDigit ascDigit → 0| 1| …| 9 uniDigit →任意Unicode十进制数字 octit → 0| 1| …| 7 hexit → 数字 | A| …| F| a| …|f 十进制 → 位 { 位数 } 八进制 → octit { octit } 十六进制 → hexit { hexit } 整数 → …

1
C ++编译器如何找到extern变量?
我用g ++和clang ++编译该程序。有一个区别: g ++打印1,而clang ++打印2。 似乎 g ++:extern变量在最短范围内定义。 clang ++:extern变量是在最短的全局范围内定义的。 C ++规范对此有任何规范吗? main.cpp #include &lt;iostream&gt; static int i; static int *p = &amp;i; int main() { int i; { extern int i; i = 1; *p = 2; std::cout &lt;&lt; i &lt;&lt; std::endl; } } other.cpp int i; 版本:g …

2
为什么`std :: basic_ios`具有公共构造函数?
std::basic_ios有一个公共的构造函数: explicit basic_ios (std::basic_streambuf&lt;CharT,Traits&gt;* sb); IMO,一个类具有公共构造函数的唯一原因是在程序中使用该类的独立实例。如果仅存在一个类以使其他类从其派生(如的情况basic_ios),则该类的所有构造函数都应为protected。的构造函数std::ios_base均受保护。但是,由于某种原因,该标准的设计者将这一构造函数basic_ios公开了。 basic_ios用作几种流类型的基类,并且我不能设想用例中至少有一个不是a basic_istream或的用例basic_ostream。有一个吗?

2
程序永远不会终止有效的C ++程序吗?
是否需要终止程序?换句话说,是一个在技术上永远无法运行的程序吗?请注意,这与空循环无关。谈论永远做“东西”(即可观察到的行为)的程序。 例如这样的事情: int main() { while (true) { try { get_input(); // calls IO process(); put_output(); // calls IO, has observable behavior // never break, exit, terminate, etc } catch(...) { // ignore all exceptions // don't (re)throw // never go out of loop } } } 这更多是一个学术问题,因为根据经验,所有理智的编译器都会为上述程序生成预期的代码(当然,假设没有其他UB来源)。是的,当然,有很多程序永远都不会终止(操作系统,嵌入式服务器)。但是有时标准是古怪的,因此是个问题。 切线:“算法”的许多(某些)定义要求算法必须终止,即,一系列永不终止的运算不被视为算法。 相切的。暂停问题指出,无法存在一种算法来确定任意程序是否针对输入完成。但是,对于该特定程序,由于没有导致退出main的分支,因此编译器可以轻松确定该程序永远不会结束。但是,这是无关紧要的,因为问题是语言律师。

1
当空基类也是成员变量时,为什么禁止空基优化?
空基优化非常棒。但是,它具有以下限制: 如果空基类之一也是第一个非静态数据成员的类型或类型的基,则禁止空基优化,因为相同类型的两个基子对象需要在对象表示中具有不同的地址最派生的类型。 要解释此限制,请考虑以下代码。该static_assert会失败。而将Foo或更改为或Bar从继承Base2将避免错误: #include &lt;cstddef&gt; struct Base {}; struct Base2 {}; struct Foo : Base {}; struct Bar : Base { Foo foo; }; static_assert(offsetof(Bar,foo)==0,"Error!"); 我完全了解这种行为。我不明白的是为什么存在这种特殊行为。显然添加它是有原因的,因为它是显式添加,而不是疏忽。这样做的理由是什么? 特别是为什么要要求两个基本子对象具有不同的地址?在上面,Bar是一个类型,并且foo是该类型的成员变量。我看不出为什么基类对Bar类型为的基类很重要foo,反之亦然。 确实,如果有的话,我希望它&amp;foo与Bar包含它的实例的地址相同,因为在其他情况下它是必需的(1)。毕竟,我对virtual继承没有任何幻想,无论如何基类都是空的,并且带有的编译Base2显示在这种特殊情况下没有任何中断。 但是显然,这种推理在某种程度上是不正确的,并且在其他情况下,也需要这种限制。 假设答案应该针对C ++ 11或更高版本(我目前正在使用C ++ 17)。 (1)注意:EBO在C ++ 11中进行了升级,并且特别成为StandardLayoutTypes的必需项(尽管Bar,上面不是StandardLayoutType)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.