从派生 class 自动转换为基础 class' 成员变量的类型
Automatic conversion from derived class to base class' member variable's type
长话短说:我想了解为什么下面代码的最后一行没有使用 D::operator B() const
转换运算符,因此在使用 g++ -std=c++17 source.cpp
编译时失败(使用不过 g++ -std=c++2a deleteme.cpp
是成功的)。
错误是:
$ g++ -std=c++17 deleteme.cpp && ./a.out
In file included from /usr/include/c++/10.2.0/cassert:44,
from deleteme.cpp:1:
deleteme.cpp: In function ‘int main()’:
deleteme.cpp:19:14: error: no match for ‘operator==’ (operand types are ‘D’ and ‘B’)
19 | assert(d == B{2}); // conversion operator not invoked explicitly errors // LINE
| ~ ^~ ~~~~
| | |
| D B
In file included from /usr/include/c++/10.2.0/utility:70,
from deleteme.cpp:2:
/usr/include/c++/10.2.0/bits/stl_pair.h:466:5: note: candidate: ‘template<class _T1, class _T2> constexpr bool std::operator==(const std::pair<_T1, _T2>&, const std::pair<_T1, _T2>&)’
466 | operator==(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
| ^~~~~~~~
/usr/include/c++/10.2.0/bits/stl_pair.h:466:5: note: template argument deduction/substitution failed:
In file included from /usr/include/c++/10.2.0/cassert:44,
from deleteme.cpp:1:
deleteme.cpp:19:20: note: ‘B’ is not derived from ‘const std::pair<_T1, _T2>’
19 | assert(d == B{2}); // conversion operator not invoked explicitly errors // LINE
|
密码是:
#include <cassert>
#include <utility>
struct B {
int x;
B(int x) : x(x) {}
bool operator==(B const& other) const { return x == other.x; }
};
struct D : std::pair<B,char*> {
operator B() const { return this->first; }
};
int main() {
B b{1};
D d{std::pair<B,char*>(B{2},(char*)"hello")};
assert((B)d == B{2}); // conversion operator invoked explicitly is fine
assert(d == B{2}); // conversion operator not invoked explicitly errors // LINE
}
此问题是 的后续问题。在那里我得到帮助写了一个 class Recursive
,它的行为就像一对(因此继承自它),其 first
是一个 std::array
并且其第二个是 boost::hana::optional<std::vector<...>>
(详见link)。
由于 std::pair
的 second
是 first
中包含的内容的一种“高级”信息,因此在很多地方我想 cast/convert 这个 std::pair
的对象-like class Recursive
到它的 first
.
的类型
当编译器看到 d == B{2}
时,它首先 creates a list of operator==
overloads 它能够找到的,然后对它们执行重载解析。
如 link 所述,重载列表包含:
- 第一个操作数的成员
operator==
s,如果有的话。
- Non-member
operators==
通过不合格查找找到,如果有的话。
- Built-in
operator==
s,如果你的操作数可以转换为built-in类型。
没有提到检查第一个操作数的转换运算符,因此找不到您的 operator==
。
解决办法是使operator==
non-member(可能定义为friend
)。这有效:
friend bool operator==(const B &a, const B &b) {return a.x == b.x;}
从C++20开始,比较运算符的规则放宽了:编译器也会在第二个操作数中寻找成员operator==
,并会愉快地调用non-member operator==
参数顺序错误。
所以 a == b
和 b == a
现在等同于学位,除了:
- 以这种新方式调用的
operator==
必须 return bool
.
- 如果有选择,编译器将更喜欢调用
operator==
的旧方法而不是调用 rhs 的成员 operator==
,而后者又优于调用 non-member operator==
参数顺序错误。
长话短说:我想了解为什么下面代码的最后一行没有使用 D::operator B() const
转换运算符,因此在使用 g++ -std=c++17 source.cpp
编译时失败(使用不过 g++ -std=c++2a deleteme.cpp
是成功的)。
错误是:
$ g++ -std=c++17 deleteme.cpp && ./a.out
In file included from /usr/include/c++/10.2.0/cassert:44,
from deleteme.cpp:1:
deleteme.cpp: In function ‘int main()’:
deleteme.cpp:19:14: error: no match for ‘operator==’ (operand types are ‘D’ and ‘B’)
19 | assert(d == B{2}); // conversion operator not invoked explicitly errors // LINE
| ~ ^~ ~~~~
| | |
| D B
In file included from /usr/include/c++/10.2.0/utility:70,
from deleteme.cpp:2:
/usr/include/c++/10.2.0/bits/stl_pair.h:466:5: note: candidate: ‘template<class _T1, class _T2> constexpr bool std::operator==(const std::pair<_T1, _T2>&, const std::pair<_T1, _T2>&)’
466 | operator==(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
| ^~~~~~~~
/usr/include/c++/10.2.0/bits/stl_pair.h:466:5: note: template argument deduction/substitution failed:
In file included from /usr/include/c++/10.2.0/cassert:44,
from deleteme.cpp:1:
deleteme.cpp:19:20: note: ‘B’ is not derived from ‘const std::pair<_T1, _T2>’
19 | assert(d == B{2}); // conversion operator not invoked explicitly errors // LINE
|
密码是:
#include <cassert>
#include <utility>
struct B {
int x;
B(int x) : x(x) {}
bool operator==(B const& other) const { return x == other.x; }
};
struct D : std::pair<B,char*> {
operator B() const { return this->first; }
};
int main() {
B b{1};
D d{std::pair<B,char*>(B{2},(char*)"hello")};
assert((B)d == B{2}); // conversion operator invoked explicitly is fine
assert(d == B{2}); // conversion operator not invoked explicitly errors // LINE
}
此问题是 Recursive
,它的行为就像一对(因此继承自它),其 first
是一个 std::array
并且其第二个是 boost::hana::optional<std::vector<...>>
(详见link)。
由于 std::pair
的 second
是 first
中包含的内容的一种“高级”信息,因此在很多地方我想 cast/convert 这个 std::pair
的对象-like class Recursive
到它的 first
.
当编译器看到 d == B{2}
时,它首先 creates a list of operator==
overloads 它能够找到的,然后对它们执行重载解析。
如 link 所述,重载列表包含:
- 第一个操作数的成员
operator==
s,如果有的话。 - Non-member
operators==
通过不合格查找找到,如果有的话。 - Built-in
operator==
s,如果你的操作数可以转换为built-in类型。
没有提到检查第一个操作数的转换运算符,因此找不到您的 operator==
。
解决办法是使operator==
non-member(可能定义为friend
)。这有效:
friend bool operator==(const B &a, const B &b) {return a.x == b.x;}
从C++20开始,比较运算符的规则放宽了:编译器也会在第二个操作数中寻找成员operator==
,并会愉快地调用non-member operator==
参数顺序错误。
所以 a == b
和 b == a
现在等同于学位,除了:
- 以这种新方式调用的
operator==
必须 returnbool
. - 如果有选择,编译器将更喜欢调用
operator==
的旧方法而不是调用 rhs 的成员operator==
,而后者又优于调用 non-memberoperator==
参数顺序错误。