簡體   English   中英

覆蓋 std::variant::operator==

[英]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::testNS::subNS::subtest可以工作,因為它們不需要依賴 ADL 來查找NS中包含的operator==的定義。

正如評論中已經提到的那樣,解決方案是將operator==定義在可以找到的某個地方——在這種情況下,它將在::NS::structs中。

我認為@Eljay 現在已經回答了這個問題:

[將] operator== 放在 NS::structs 中。

相關條款是 3. a) 在https://en.cppreference.com/w/cpp/language/adl中:

  1. 對於類型為 class 模板特化的 arguments,除了 class 規則外,還會檢查以下類型並將其關聯的類和命名空間添加到集合中

    a) 為類型模板參數提供的所有模板 arguments 的類型(跳過非類型模板參數和跳過模板模板參數)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM