Questions tagged «language-lawyer»

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

1
__func__指针的两个constexpr实例的区别是否仍然是constexpr?
这是有效的C ++吗? int main() { constexpr auto sz = __func__ - __func__; return sz; } GCC和MSVC认为可以,而Clang认为不可以:Compiler Explorer。 所有编译器都同意这是可以的:Compiler Explorer。 int main() { constexpr auto p = __func__; constexpr auto p2 = p; constexpr auto sz = p2 - p; return sz; } Clang再次不喜欢这个,但是其他的都可以:Compiler Explorer int main() { constexpr auto p …

1
这是std :: gcd中的错误吗?
我遇到了这种std::gcd意外的行为: #include <iostream> #include <numeric> int main() { int a = -120; unsigned b = 10; //both a and b are representable in type C using C = std::common_type<decltype(a), decltype(b)>::type; C ca = std::abs(a); C cb = b; std::cout << a << ' ' << ca << '\n'; std::cout << …

2
如果琐碎的默认构造函数不执行任何操作,为什么不能使用malloc创建琐碎的可构造对象?
我很难理解cppreference引用的有关普通默认构造函数的以下段落。我已经搜索了stackoverflow,但仍然没有一个明确的答案。所以请帮忙。 普通的默认构造函数是不执行任何操作的构造函数。与C语言兼容的所有数据类型(POD类型)都是默认可构造的。但是,与C语言不同,不能通过简单地重新解释适当对齐的存储来创建具有琐碎默认构造函数的对象,例如,用std :: malloc分配的内存:正式引入新对象并避免潜在的未定义行为时,需要placement-new。 具体来说,如果琐碎的默认构造函数什么都不做,为什么我们不能重新解释存储并假装存在具有给定类型的对象?您能否提供一些可能导致未定义行为的示例?

4
如何在C ++ 11中实现StoreLoad障碍?
我想编写可移植的代码(Intel,ARM,PowerPC ...)来解决经典问题的变体: Initially: X=Y=0 Thread A: X=1 if(!Y){ do something } Thread B: Y=1 if(!X){ do something } 其中的目的是为了避免在这两个线程都在做的情况something。(如果两者都不运行,这很好;这不是一次运行的机制。)如果您在下面的推理中发现一些缺陷,请更正我。 我知道,我可以通过memory_order_seq_cst原子stores和loads 实现目标,如下所示: std::atomic<int> x{0},y{0}; void thread_a(){ x.store(1); if(!y.load()) foo(); } void thread_b(){ y.store(1); if(!x.load()) bar(); } 之所以能够达到目标,是因为 {x.store(1), y.store(1), y.load(), x.load()}事件上必须有一些总订单,并且必须与程序订单的“优势”相符: x.store(1) “在TO之前” y.load() y.store(1) “在TO之前” x.load() 如果foo()被调用,那么我们还有其他优势: y.load() “先读值” y.store(1) …

4
cppreference中对宽松顺序的解释是否错误?
在cppreference.com的文档中std::memory_order,有一个宽松订购的示例: 轻松订购 带标签的原子操作memory_order_relaxed不是同步操作;它们不会在并发内存访问之间强加顺序。它们仅保证原子性和修改顺序的一致性。 例如,如果x和y最初为零, // Thread 1: r1 = y.load(std::memory_order_relaxed); // A x.store(r1, std::memory_order_relaxed); // B // Thread 2: r2 = x.load(std::memory_order_relaxed); // C y.store(42, std::memory_order_relaxed); // D 被允许以产生R1 == R2 == 42,因为尽管A被测序-之前线程1中B和C 之前测序线程2内d,没有什么阻止由在y的修改次序出现A之前D和B,从按x的修改顺序出现在C之前。D在y上的副作用对于线程1中的负载A可见,而B在x上的副作用对于线程2中的负载C可见。特别是,如果D在C in之前完成,则可能发生这种情况。线程2,由于编译器重新排序或在运行时。 它说:“在线程2中,C在D之前被排序”。 根据可以在评估顺序中找到的按顺序排序的定义,如果A在B之前排序,则A的评估将在B的评估开始之前完成。由于C在线程2中在D之前被排序,因此C必须在D开始之前完成,因此快照的最后一句的条件部分将永远无法满足。

2
如果constexpr在lambda中带有static_assert,哪个编译器正确?
当我们要在中使用时static_assert,if constexpr必须使条件取决于某些模板参数。有趣的是,当代码包装在lambda中时,gcc和clang不同意。 以下代码使用gcc进行编译,但是clang触发断言,即使if constexpr不能为true。 #include <utility> template<typename T> constexpr std::false_type False; template<typename T> void foo() { auto f = [](auto x) { constexpr int val = decltype(x)::value; if constexpr(val < 0) { static_assert(False<T>, "AAA"); } }; f(std::integral_constant<int, 1>{}); } int main() { foo<int>(); } 这里的例子。 它可以很容易地通过用固定False<T>通过False<decltype(x)>。 所以问题是:哪个编译器正确?我认为gcc是正确的,因为中的条件static_assert取决于T,但是我不确定。

2
Derived1 :: Base和Derived2 :: Base是否引用相同的类型?
MSVC,Clang和GCC在以下代码上存在分歧: struct Base { int x; }; struct Der1 : public Base {}; struct Der2 : public Base {}; struct AllDer : public Der1, public Der2 { void foo() { Der1::Base::x = 5; } }; 哥德宝 GCC: <source>: In member function 'void AllDer::foo()': <source>:10:21: error: 'Base' is an ambiguous base …

1
是什么防止班级中相邻成员的重叠?
考虑以下三个struct: class blub { int i; char c; blub(const blub&) {} }; class blob { char s; blob(const blob&) {} }; struct bla { blub b0; blob b1; }; 在int4字节的典型平台上,大小,对齐方式和总填充1如下: struct size alignment padding -------- ------ ----------- --------- blub 8 4 3 blob 1 1 0 bla 12 4 6 …

1
在Haskell中评估函数->()有什么规则?
就像标题中所说的那样:对Haskell函数返回单元进行评估有什么保证?有人会认为在这种情况下无需运行任何类型的评估,()除非存在明确的严格性要求,否则编译器可以将所有此类调用替换为立即值,在这种情况下,代码可能必须决定是否应返回()或底部。 我已经在GHCi中对此进行了实验,似乎发生了相反的情况,也就是说,似乎正在评估这种功能。一个非常原始的例子是 f :: a -> () f _ = undefined f 1由于存在,评估会引发错误undefined,因此肯定会发生某些评估。但是,尚不清楚评估的深度。有时它看起来像需要评估返回函数的所有调用一样深入()。例: g :: [a] -> () g [] = () g (_:xs) = g xs 如果使用,此代码将无限循环g (let x = 1:x in x)。但是之后 f :: a -> () f _ = undefined h :: a -> () h _ …


4
使用非布尔返回值重载相等比较时,C ++ 20中的更改中断还是clang-trunk / gcc-trunk中的回归?
以下代码在c ++ 17模式下使用clang-trunk可以正常编译,但在c ++ 2a(即将到来的c ++ 20)模式下可以中断: // Meta struct describing the result of a comparison struct Meta {}; struct Foo { Meta operator==(const Foo&) {return Meta{};} Meta operator!=(const Foo&) {return Meta{};} }; int main() { Meta res = (Foo{} != Foo{}); } 它还可以使用gcc-trunk或clang-9.0.0进行编译:https : //godbolt.org/z/8GGT78 clang-trunk和错误-std=c++2a: <source>:12:19: error: use …

1
为什么在使用不相关的接口类型调用时,编译器为什么选择带有类类型参数的通用方法?
考虑以下两个类和接口: public class Class1 {} public class Class2 {} public interface Interface1 {} 为什么第二个调用mandatory使用Class2,如果getInterface1和Interface1没有关系来调用重载方法Class2? public class Test { public static void main(String[] args) { Class1 class1 = getClass1(); Interface1 interface1 = getInterface1(); mandatory(getClass1()); // prints "T is not class2" mandatory(getInterface1()); // prints "T is class2" mandatory(class1); // prints "T is …

2
T是否必须是要在`std :: declval <T>`中使用的完整类型?
考虑以下示例(来自此处): #include &lt;type_traits&gt; #include &lt;iostream&gt; template &lt;typename U&gt; struct A { }; struct B { template &lt;typename F = int&gt; A&lt;F&gt; f() { return A&lt;F&gt;{}; } using default_return_type = decltype(std::declval&lt;B&gt;().f()); }; int main() { B::default_return_type x{}; std::cout &lt;&lt; std::is_same&lt; B::default_return_type, A&lt;int&gt;&gt;::value; } 它在gcc9.2上编译时没有错误,但gcc7.2和clang 10.0.0抱怨B未完成。lang的错误是: prog.cc:11:58: error: member access into incomplete …

1
GCC实施的尖括号包含。为什么必须如下所述?
本文档在其2.6计算的包括部分中具有以下段落: 如果该行扩展到以&lt;令牌开头并包括&gt;令牌的令牌流,则&lt;和第一个&gt;之间的令牌将合并以形成要包含的文件名。令牌之间的任何空格都减少为一个空格;那么将保留初始&lt;之后的任何空格,但忽略闭合&gt;之前的结尾空格。CPP根据尖括号包含的规则搜索文件。 我知道这是实现定义的,但是为什么GCC必须采用这种方式?我指的是上面突出显示的句子。 编辑 我刚刚注意到,上面引用的第三段之前的内容如下: 定义宏时必须小心。#define保存令牌,而不是文本。预处理器无法知道该宏将用作的参数#include,因此它会生成普通标记,而不是标头名称。如果您使用的双引号包含与字符串常量足够接近,则这不太可能引起问题。 但是,如果使用尖括号,则可能会遇到麻烦。 有谁知道这里指出了什么麻烦?
10 c++  c  gcc  language-lawyer 

2
C ++模板模板参数类型推导
我有在字符串容器中查找并打印出模式匹配项的代码。在模板化的函数foo中执行打印 编码 #include &lt;iostream&gt; #include &lt;algorithm&gt; #include &lt;iterator&gt; #include &lt;vector&gt; #include &lt;string&gt; #include &lt;tuple&gt; #include &lt;utility&gt; template&lt;typename Iterator, template&lt;typename&gt; class Container&gt; void foo(Iterator first, Container&lt;std::pair&lt;Iterator, Iterator&gt;&gt; const &amp;findings) { for (auto const &amp;finding : findings) { std::cout &lt;&lt; "pos = " &lt;&lt; std::distance(first, finding.first) &lt;&lt; " "; std::copy(finding.first, finding.second, std::ostream_iterator&lt;char&gt;(std::cout)); …

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.