在 C++20 中有一些关于重写比较运算符的新规则,我试图了解它们是如何工作的。我遇到了以下程序:
struct B {};
struct A
{
bool operator==(B const&); // #1
};
bool operator==(B const&, A const&); // #2
int main()
{
B{} == A{}; // C++17: calls #2
// C++20: calls #1
}
Run Code Online (Sandbox Code Playgroud)
这实际上破坏了现有的代码。我对此感到有些惊讶;#2实际上对我来说仍然看起来更好:p
那么这些新规则如何改变现有代码的含义呢?
令我惊讶的是,我遇到了另一个障碍,例如C++20 行为用相等运算符破坏了现有代码?.
考虑一个简单的不区分大小写的键类型,用于例如std::setor std::map:
// Represents case insensitive keys
struct CiKey : std::string {
using std::string::string;
using std::string::operator=;
bool operator<(CiKey const& other) const {
return boost::ilexicographical_compare(*this, other);
}
};
Run Code Online (Sandbox Code Playgroud)
简单的测试:
using KeySet = std::set<CiKey>;
using Mapping = std::pair<CiKey, int>; // Same with std::tuple
using Mappings = std::set<Mapping>;
int main()
{
KeySet keys { "one", "two", "ONE", "three" };
Mappings mappings {
{ "one", 1 }, { "two", 2 }, { "ONE", 1 }, { "three", …Run Code Online (Sandbox Code Playgroud) 我<=>在C ++ 20中使用新的宇宙飞船运算符遇到一种奇怪的行为。我正在将Visual Studio 2019编译器与一起使用/std:c++latest。
这段代码可以正常编译:
#include <compare>
struct X
{
int Dummy = 0;
auto operator<=>(const X&) const = default; // Default implementation
};
int main()
{
X a, b;
a == b; // OK!
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我将X更改为:
struct X
{
int Dummy = 0;
auto operator<=>(const X& other) const
{
return Dummy <=> other.Dummy;
}
};
Run Code Online (Sandbox Code Playgroud)
我收到以下编译器错误:
error C2676: binary '==': 'X' does not define this operator or a conversion to …
P0553R4中的功能:位运算仅限于无符号整数。该提案没有给出这一限制的理由。我可以看到,如果没有定义有符号整数的位表示,这是有意义的,但使用 C++20,我们可以保证有符号整数使用二进制补码。
对我来说,允许使用有符号整数类型调用eg似乎是合理的std::popcount,因为实现可以简单地转换为相应的无符号类型以在无符号域中执行位操作。
P0553R4添加这个约束的原因是什么?(只是 P0553R4 和 P0907R4 之间缺少同步吗?)
我注意到大多数(如果不是所有)容器现在都需要它们的::iterator类型LegacySomethingIterator而不是SomethingIterator.
例如,std::vector<>::iterator 现在需要:
iteratorLegacyRandomAccessIterator
这似乎是大多数其它容器一样,都是需要自己迭代器从去SomethingIterator到LegacySomethingIterator.
还有"新"要求采用旧要求的名称,例如RandomAccessIterator,为什么这些要求被添加?在我看来,新的变种只会影响遗留的变种,没有差异.
为什么首先创建新的,他们的要求对我来说是一样的.为什么新的只是替换旧的要求而不是现在有两个不同的名称(例如RandomAccessIterator和LegacyRandomAccessIterator)?
我们考虑使用完全相同的语法创建两种不同类型的目标。这可以通过lambdas轻松完成:
auto x = []{};
auto y = []{};
static_assert(!std::is_same_v<decltype(x), decltype(y)>);
Run Code Online (Sandbox Code Playgroud)
但是,我们正在寻找另一种更优雅的语法,而不是使用lambda。这是一些测试。我们首先定义一些工具:
#include <iostream>
#include <type_traits>
#define macro object<decltype([]{})>
#define singleton object<decltype([]{})>
constexpr auto function() noexcept
{
return []{};
}
template <class T = decltype([]{})>
constexpr auto defaulted(T arg = {}) noexcept
{
return arg;
}
template <class T = decltype([]{})>
struct object
{
constexpr object() noexcept {}
};
template <class T>
struct ctad
{
template <class... Args>
constexpr ctad(const Args&...) noexcept {}
};
template <class... Args>
ctad(const Args&...) -> …Run Code Online (Sandbox Code Playgroud) 考虑以下程序:
#include <iostream>
#include <type_traits>
constexpr int f() {
if (std::is_constant_evaluated())
return -1;
else return 1;
}
int main() {
int const i = f();
std::cout << i;
}
Run Code Online (Sandbox Code Playgroud)
它打印-1在运行时(wandbox)。
但是,如果我throw在编译时求值时使用该函数:
#include <iostream>
#include <type_traits>
constexpr int f() {
if (std::is_constant_evaluated())
throw -1; // <----------------------- Changed line
else return 1;
}
int main() {
int const i = f();
std::cout << i;
}
Run Code Online (Sandbox Code Playgroud)
它可以编译并输出1(wandbox)。为什么我没有出现编译失败?
我正在为此代码使用 g++ 10.2。没有任何人知道为什么我得到一个编译错误在过去std::views::reverse的results3?
#include <vector>
#include <ranges>
int main() {
auto values = std::vector{1,2,3,4,5,6,7,8,9,10};
auto even = [](const auto value) {
return value % 2 == 0;
};
auto square = [](const auto value) {
return value * value;
};
auto results1 = values
| std::views::filter(even)
| std::views::reverse
| std::views::take(4)
| std::views::reverse;
auto results2 = values
| std::views::transform(square)
| std::views::reverse
| std::views::take(4)
| std::views::reverse;
auto results3 = values
| std::views::filter(even)
| std::views::transform(square)
| std::views::reverse
| std::views::take(4) …Run Code Online (Sandbox Code Playgroud) struct A {
consteval A() {};
};
constexpr bool g() {
auto a = new A;
delete a;
return true;
}
int main() {
static_assert(g());
}
Run Code Online (Sandbox Code Playgroud)
https://godbolt.org/z/jsq35WxKs
GCC 和 MSVC 拒绝该程序,ICC 和 Clang 接受它:
///MSVC:
<source>(6): error C7595: 'A::A': call to immediate function is not a constant expression
Compiler returned: 2
//GCC:
<source>: In function 'constexpr bool g()':
<source>:6:18: error: the value of '<anonymous>' is not usable in a constant expression
6 | auto a = new A;
| ^ …Run Code Online (Sandbox Code Playgroud) 升级到最新的 Visual Studio 2022 版本 17.6 后,我们的自定义视图之一停止被识别为std::ranges::range. 事实证明,问题出在视图的迭代器中operator ==。operator !=
请找到下面的最小简化示例(已经没有视图和迭代器):
struct A {
friend bool operator ==( const A &, const A & ) = default;
};
struct B {
friend bool operator ==( const B &, const B & ) = default;
friend bool operator ==( const B &, const A & ) { return false; }
// Visual Studio 2022 version 17.6 does not like next line
friend bool operator !=( const …Run Code Online (Sandbox Code Playgroud) c++ ×10
c++20 ×10
c++-concepts ×2
constexpr ×2
c++17 ×1
consteval ×1
lambda ×1
std-ranges ×1
stdtuple ×1