c++ - C++20:自动生成的运算符在派生类中不可引用?
问题描述
在编写与宇宙飞船运算符相关的 C++20 时,我注意到一些相当奇怪的东西。
据我了解,从 C++20 开始,比较运算符是由编译器自动生成的。但是,我遇到了一个关于自动生成运算符的有趣问题。
在下面的代码中,我试图定义MyIterator
哪个派生自vector<int>::iterator
. 现在我希望基类受到保护并显式地公开函数。所以很自然地,我使用using
声明来使用基类中的成员函数。但是,编译器抱怨operator!=
缺少!
发生这种情况是因为自动生成的运算符“生成得太晚”吗?
有趣的是,定义中显示的解决方法MyIterator2
似乎可以解决问题。
我想听听这种奇怪行为的原因。这是通过 spaceship 运算符自动生成的运算符的预期行为吗?或者这是编译器错误还是未实现的功能?
编译器版本信息:
[hoge@foobar]$ clang++ --version
clang version 10.0.1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
代码(main.cpp):
#include <vector>
using MyVec = std::vector<int>;
/// Does not compile
class MyIterator : protected MyVec::iterator {
using Base = MyVec::iterator;
// Error
// No member named 'operator!=' in '__gnu_cxx::__normal_iterator<int *,
// std::vector<int, std::allocator<int>>>'clang(no_member)
using Base::operator!=;
};
/// Compiles
class MyIterator2 : protected MyVec::iterator {
using Base = MyVec::iterator;
/// A rather ugly workaround!
auto operator!=(const MyIterator2 &o) const {
return static_cast<const Base &>(*this) != static_cast<const Base &>(o);
}
};
补充笔记:
GCC 也以同样的方式拒绝代码。
[hoge@foobar tmp]$ g++ --version
g++ (GCC) 10.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[hoge@foobar tmp]$ g++ main.cpp
main.cpp:12:23: error: ‘operator!=’ has not been declared in ‘__gnu_cxx::Base’
12 | using Base::operator!=;
|
解决方案
据我了解,从 C++20 开始,比较运算符是由编译器自动生成的。但是,我遇到了一个关于自动生成运算符的有趣问题。
这是不正确的。不生成比较运算符。比较表达式被重写。
也就是说,给定:
struct X {
int i;
bool operator==(X const&) const = default;
};
X{2} == X{3}
是直接有效的,调用 defaulted operator==
,它进行成员比较,从而产生false
.
X{2} != X{3}
也是一个有效的表达式,但它不调用任何名为operator!=
. 没有这样的功能。相反,它评估为!(X{2} == X{3})
,产生true
。尽管X{2} != X{3}
是一个有效的表达式,但operator!=
这里的任何地方都没有任何名称,因此您不能引用任何具有该名称的内容。
所以很自然,我使用 using 声明来使用基类中的成员函数。但是,编译器抱怨
operator!=
缺少!
在 C++20 中,我们几乎从不需要operator!=
.,因此几乎所有这些都从标准库规范中删除,标准库很可能会通过并#ifdef
删除它们。需要解析的代码更少。由于运算符重写,不等式表达式仍然有效,但operator!=
不再有任何名称。
所以你不能using
。
但是标准库不再需要的同样原因operator!=
也适用于你——你也不需要它。
进一步注意,即使在 C++17 中也不能保证using Base::operator!=;
有效,因为没有义务operator!=
将其编写为成员函数。它本来可以写成一个自由函数,然后这无论如何都不会起作用,即使在operator!=
其他地方会有一个名为 ... 的函数。
推荐阅读
- ios - 呈现警报控制器后,TableView(didSelectRowAt IndexPath)中的 Swift Continue Flow
- c# - Artefact Animator 的替代品
- objective-c - Swift 或 Objective C 中枚举器和迭代器的区别
- android - 查看寻呼机未正确显示
- asp.net - 如何在 aspx 页面的 TemplateField 中添加 DataFormatString?
- docker - 如何将“npm install”集成到 ASP.NET CORE 2.1 Docker 构建中
- php - 用户通过 POST 路由提交表单后立即注销
- visual-c++ - C 中 Visual Studio 中的内存泄漏
- laravel - 如何正确地将 node_modules 中的库包含到您的项目中?
- spring - 从控制器显示错误或成功