我在调试这个问题的时候碰到了这个。
我把它删减到只使用Boost运算符:
>
编译器资源管理器C++17 C++20
#include <boost/operators.hpp>
struct F : boost::totally_ordered1<F, boost::totally_ordered2<F, int>> {
/*implicit*/ F(int t_) : t(t_) {}
bool operator==(F const& o) const { return t == o.t; }
bool operator< (F const& o) const { return t < o.t; }
private: int t;
};
int main() {
#pragma GCC diagnostic ignored "-Wunused"
F { 42 } == F{ 42 }; // OKAY
42 == F{42}; // C++17 OK, C++20 infinite recursion
F { 42 } == 42; // C++17 OK, C++20 infinite recursion
}
这个程序可以在GCC和CLANG中用C++17(启用了UBSAN/ASAN)编译并运行良好。
当您将隐式构造函数更改为explicit
时,有问题的行显然不再在C++17上编译
令人惊讶的是,这两个版本都在C++20(v1和v2)上编译,但它们导致了在C++17上无法编译的两行上的无限递归(崩溃或紧密循环,取决于优化级别)。
显然,这种通过升级到C++20而潜入的无声bug是令人担忧的。
问题:
的确,C++20不幸地使这段代码无限递归。
下面是一个简化的示例:
struct F {
/*implicit*/ F(int t_) : t(t_) {}
// member: #1
bool operator==(F const& o) const { return t == o.t; }
// non-member: #2
friend bool operator==(const int& y, const F& x) { return x == y; }
private:
int t;
};
让我们看看42==F{42}
。
在C++17中,我们只有一个候选者:非成员候选者(#2
),所以我们选择它。其主体x==y
本身只有一个候选项:成员候选项(#1
),它涉及将y
隐式转换为f
。然后,成员候选比较两个整数成员,这是完全好的。
在C++20中,初始表达式42==F{42}
现在有两个候选项:一个是以前的非成员候选项(#2
),另一个是反向成员候选项(#1
反向)。#2
是更好的匹配--我们精确匹配两个参数,而不是调用一个转换,因此选择了它。
但是,x==y
现在有两个候选项:成员候选项(#1
),还有反向的非成员候选项(#2
反向)。#2
是更好的匹配,原因与之前的匹配相同:不需要转换。因此我们改为计算y==x
。无限递归。
非反转的候选人优先于反转的候选人,但仅作为抢七者。更好的转换顺序总是第一。
好吧太好了,我们怎么解决它?最简单的选择是完全删除非成员候选人:
struct F {
/*implicit*/ F(int t_) : t(t_) {}
bool operator==(F const& o) const { return t == o.t; }
private:
int t;
};
42==F{42}
在这里的计算结果为F{42}。operator==(42)
,可以正常工作。
如果我们想要保留非成员候选人,我们可以显式地添加它的反向候选人:
struct F {
/*implicit*/ F(int t_) : t(t_) {}
bool operator==(F const& o) const { return t == o.t; }
bool operator==(int i) const { return t == i; }
friend bool operator==(const int& y, const F& x) { return x == y; }
private:
int t;
};
这使得42==F{42}
仍然选择非成员候选者,但现在在正文中的x==y
将选择成员候选者,这将执行正常的相等。
最后一个版本还可以删除非成员候选。以下方法也适用于所有测试用例,而不需要递归(这也是我接下来在C++20中编写比较的方法):
struct F {
/*implicit*/ F(int t_) : t(t_) {}
bool operator==(F const& o) const { return t == o.t; }
bool operator==(int i) const { return t == i; }
private:
int t;
};
我对这个结果很困惑。 是不同的对象,当处理时,它会比较第一个元素的地址,所以 的行为。 (*)是否等于 ? 是一个对象吗?和都指向这个物体的第一个元素?
这个问题与现有的问题“使用C11的‘自动’能提高性能吗?” 这个问题的一个答案表明,使用不仅会有积极的影响,也会有消极的影响。 我认为我们需要一个单独的问题,答案集中在自动的那一面。
问题内容: 来自Python,我不习惯看到超过80列的代码行。所以当我遇到这个: 我试图打破它 但是我明白了 我还尝试过按回车键并在末尾加分号来打破界限: 但是我再次得到: 所以我想知道用什么语言来做到这一点? 问题答案: 首先介绍一些背景。Go的正式语法在许多产品中都使用分号作为终止符,但是Go程序可能会省略大多数(它们应该有一个更清晰易读的源;也可以删除不必要的分号)。 该规范列出了确切的规则
GCC6有一个新的优化器特性:它假设总是不为空,并基于此进行优化。 值范围传播现在假定C++成员函数的this指针是非空的。这消除了常见的空指针检查,但也破坏了一些不一致的代码基(如Qt-5、Chromium、KDevelop)。作为临时解决办法,可以使用-fno-delete-null-pointer-checks。使用-fsanitize=undefined可以识别错误的代码。 变更文档明确指
问题内容: 以下是一个名为AT5G60410.gff的大文件的示例: 我在使用grep从中提取特定行时遇到了一些麻烦。我想提取所有在第三列中指定的“基因”或“外显子”类型的行。当这不起作用时,我感到很惊讶: 没有结果返回。我哪里出问题了? 问题答案: 您需要逃脱。以下应做的工作。
本文向大家介绍C# 格式化字符串的实现代码,包括了C# 格式化字符串的实现代码的使用技巧和注意事项,需要的朋友参考一下 1 前言 如果你熟悉Microsoft Foundation Classes(MFC)的CString,Windows Template Library(WTL)的CString或者Standard Template Library(STL)的字符串类,那么你对String