![](/img/trans.png)
[英]Configured CMake to compile in C++20 but the executable compiles in C++17
[英]operator==() code compiles w/C++17 but not C++20
這個代碼片段
#include <stdlib.h>
struct Base { };
template<typename T>
inline bool operator==(const T&, const Base&)
{
return true;
}
template<typename T>
inline bool operator!=(const T& lhs, const Base& rhs)
{
return !(lhs == rhs);
}
struct A : public Base
{
bool operator==(const A&) const { return true; }
};
struct A_1 final : public A { };
int main()
{
const A a;
const A_1 a_1;
if (a_1 != a) {}
return EXIT_SUCCESS;
}
在 C++17 (Visual Studio 2022) 中編譯沒有錯誤。 (有關更詳細的示例,請參閱C++17 operator==() 和 operator!=() code failed with C++20 ;注意在這種情況下代碼編譯。)
嘗試使用 C++20 構建相同的代碼會產生三個編譯器錯誤:
error C2666: 'operator !=': 3 overloads have similar conversions
message : could be 'bool A::operator ==(const A &) const' [rewritten expression '!(x == y)']
message : or 'bool A::operator ==(const A &) const' [synthesized expression '!(y == x)']
message : or 'bool operator !=<A_1>(const T &,const Base &)'
是的,我知道C++20 會合成operator!=
之類的……但是現有的 C++17 代碼不應該仍然用 C++20 編譯嗎?
如何解決問題,以便相同的代碼同時使用 C++17 和 C++20 進行編譯並生成相同的結果?
對派生類進行更改可能很困難,因為該代碼可能位於其他地方(這實際上是庫代碼); 這將是更喜歡以更改Base
。
這是因為所有的功能現在都是候選的,而在它們之前不是。
這意味着突然之間, A
的operator==
成為a_1 != a
的候選者。 現在允許編譯器反轉參數,將a == b
更改為!(a != b)
,反之亦然,甚至可以將順序更改為b == a
。
由於bool operator==(const A&);
代碼導致不明確的調用bool operator==(const A&);
in A
支持a_1 != a
,通過將操作反轉為!(a_1 == a)
並更改參數順序以最終獲得!(a == a_1)
作為候選對象。
對此有多種解決方案。
一種是通過繼承函數簡單地使一個候選人變得更好:
struct A_1 final : public A { using A::operator==; };
另一種是限制操作員只與A
一起工作:
struct A : public Base
{
friend bool operator==(std::same_as<A> auto const&, std::same_as<A> auto const&) { return true; }
};
另一種不需要更改A
或A_1
解決方案是添加一個重載,該重載始終是Base
的理想候選對象作為友元函數。
整個代碼在 C++20 中變成了這樣:
struct Base {
friend bool operator==(std::derived_from<Base> auto const&, std::derived_from<Base> auto const&) { return true; }
};
struct A : Base {};
struct A_1 final : A {};
您可以刪除全局命名空間中的模板函數,也可以刪除派生類中的函數。
您不需要刪除A
中的函數,但它不會被調用並且生成的代碼仍然會非常令人驚訝。
但是,請注意您的代碼之前已損壞。
這是在 C++17 中使用operator==
代碼的編譯器輸出:
int main()
{
const A a;
const A_1 a_1;
if (!(a_1 == a)) {}
return EXIT_SUCCESS;
}
編譯器輸出:
<source>: In function 'int main()':
<source>:26:15: error: ambiguous overload for 'operator==' (operand types are 'const A_1' and 'const A')
26 | if (!(a_1 == a)) {}
| ~~~ ^~ ~
| | |
| | const A
| const A_1
<source>:17:10: note: candidate: 'bool A::operator==(const A&) const'
17 | bool operator==(const A&) const { return true; }
| ^~~~~~~~
<source>:5:13: note: candidate: 'bool operator==(const T&, const Base&) [with T = A_1]'
5 | inline bool operator==(const T&, const Base&)
| ^~~~~~~~
ASM generation compiler returned: 1
C++20 只會接受更少的具有令人驚訝的行為的代碼。
它的罰款,如果你刪除A::operator==
。
A::operator==
真的沒有意義,因為模板說一切都等於Base
。
但是現有的 C++17 代碼不應該仍然用 C++20 編譯嗎?
委員會努力盡量減少破壞性更改,但他們不保證不會有任何更改。 在這種情況下,人們認為讓==
成為等價關系比保持現有行為更重要。 正如鏈接的問題所指出的,多態相等性測試通常是錯誤的來源。
C++ 擴展了關系運算符的重載解析以包含交換的參數,這在診斷消息中:
所以你需要更少的操作員。 事實上,您可以考慮重載/默認三向比較運算符 ( <=>
)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.