[英]Overriding std::variant::operator==
我有點驚訝將變體的替代類型放入子命名空間似乎會破壞operator==
:
#include <variant>
#include <iostream>
namespace NS {
namespace structs {
struct A {};
struct B {};
} // namespace structs
using V = std::variant<structs::A, structs::B>;
bool operator==(const V& lhs, const V& rhs)
{
return lhs.index() == rhs.index();
}
std::string test(const V& x, const V& y)
{
if (x == y) {
return "are equal";
} else {
return "are not equal";
}
}
namespace subNS {
std::string subtest(const V& x, const V& y)
{
if (x == y) {
return "are equal";
} else {
return "are not equal";
}
}
} // namespace subNS
} // namespace NS
int main() {
const auto u = NS::V{NS::structs::A{}};
const auto v = NS::V{NS::structs::A{}};
const auto w = NS::V{NS::structs::B{}};
// Why doesn't this work?
// It does work if A and B are defined in NS rather than NS::structs.
//std::cout << "u and v are " << (u == v ? "equal" : "not equal") << "\n";
//std::cout << "u and w are " << (u == w ? "equal" : "not equal") << "\n";
std::cout << "u and v " << NS::test(u, v) << "\n";
std::cout << "u and w " << NS::test(u, w) << "\n";
std::cout << "u and v " << NS::subNS::subtest(u, v) << "\n";
std::cout << "u and w " << NS::subNS::subtest(u, w) << "\n";
}
我找到的唯一解決方案是定義:
namespace std {
template<>
constexpr bool
operator==(const NS::V& lhs, const NS::V& rhs)
{
return lhs.index() == rhs.index();
}
} // namespace std
但這看起來有點可疑,並且似乎從 c++20 被禁止: https://en.cppreference.com/w/cpp/language/extending_std#Function_templates_and_member_functions_of_templates
有更好的想法嗎? 顯然,我試圖避免為每種替代類型添加operator==
。
原因是由於 ADL。 特別是,請參閱[basic.lookup.argdep]/2 :(強調我的)
對於 function 調用中的每個參數類型 T,需要考慮一組零個或多個關聯命名空間和一組零個或多個關聯實體(命名空間除外)。 命名空間和實體集完全由 function arguments 的類型(以及任何模板模板參數的命名空間)確定。 用於指定類型的 Typedef 名稱和 using-declarations 不構成該集合。 命名空間和實體集通過以下方式確定:
- ...
- 如果 T 是 class 類型(包括聯合),則其關聯實體是: class 本身; class,如果有的話; 及其直接和間接基類。 其關聯的命名空間是其關聯實體的最內層封閉的命名空間。 此外,如果 T 是 class 模板特化,則其關聯的命名空間和實體還包括: 為模板類型參數(不包括模板模板參數)提供的模板 arguments 的類型相關的命名空間和實體; 用作模板模板 arguments 的模板; 任何模板模板 arguments 是其成員的命名空間; 以及用作模板模板arguments的任何成員模板是其成員的類。
特別是,“使用聲明” V
存在於::NS
中這一事實不會影響依賴於參數的查找。 唯一考慮的命名空間是::std
,來自std::variant
和::NS::structs
,來自<structs::A, structs::B>
模板 arguments。
NS::test
和NS::subNS::subtest
可以工作,因為它們不需要依賴 ADL 來查找NS
中包含的operator==
的定義。
正如評論中已經提到的那樣,解決方案是將operator==
定義在可以找到的某個地方——在這種情況下,它將在::NS::structs
中。
我認為@Eljay 現在已經回答了這個問題:
[將] operator== 放在 NS::structs 中。
相關條款是 3. a) 在https://en.cppreference.com/w/cpp/language/adl中:
對於類型為 class 模板特化的 arguments,除了 class 規則外,還會檢查以下類型並將其關聯的類和命名空間添加到集合中
a) 為類型模板參數提供的所有模板 arguments 的類型(跳過非類型模板參數和跳過模板模板參數)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.