首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >覆盖std::variant::operator==

覆盖std::variant::operator==
EN

Stack Overflow用户
提问于 2020-12-08 13:09:49
回答 2查看 155关注 0票数 0

我有点惊讶,将变体的替代类型放入子命名空间似乎会破坏operator==

代码语言:javascript
复制
#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";
}

我找到的唯一解决办法是定义:

代码语言:javascript
复制
namespace std {

template<>
constexpr bool
operator==(const NS::V& lhs, const NS::V& rhs)
{
    return lhs.index() == rhs.index();
}

} // namespace std

但这看上去有些可疑,似乎被禁止在c++20:模板中使用。

有更好的主意吗?显然,我试图避免为每种可选类型添加operator==

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-12-08 21:45:12

原因是由于ADL。特别是,请参见[basic.lookup.argdep]/2:(强调我的)

对于函数调用中的每个参数类型T,有一组零或多个关联命名空间和一组零或多个关联实体(名称空间除外)需要考虑。命名空间和实体的集合完全由函数参数的类型(以及任何模板模板参数的命名空间)决定。用于指定类型的类型名称和使用-声明对此集没有贡献。名称空间和实体集的确定方式如下:

  • ..。
  • 如果T是类类型(包括联合),则它的关联实体是:类本身的;类的成员(如果有的话);以及它的直接和间接基类。它的关联命名空间是其关联实体最内部的名称空间。此外,如果T是类模板专门化,则其关联的命名空间和实体还包括:与模板类型参数提供的模板参数类型相关联的命名空间和实体(不包括模板模板参数);用作模板参数的模板;任何模板参数为成员的命名空间;以及用作模板模板参数的任何成员模板都是成员的类。

特别是,“使用-声明”V存在于::NS中这一事实并不影响依赖于参数的查找。唯一考虑的命名空间是::stdstd::variant::NS::structs,它们来自<structs::A, structs::B>模板参数。

NS::testNS::subNS::subtest之所以工作,是因为它们不需要依赖ADL来找到包含在NS中的operator==的定义。

正如注释中已经提到的,解决方案是在某个地方定义operator== --在本例中,这将是在::NS::structs中定义的。

票数 1
EN

Stack Overflow用户

发布于 2020-12-08 17:56:42

我认为@Eljay现在已经回答了这个问题:

将operator==放在NS::structs中。

相关的子句是https://en.cppreference.com/w/cpp/language/adl中的3.a)

  1. 对于类型为类模板专门化的参数,除了类规则外,还将检查以下类型,并将它们的关联类和命名空间添加到集合中 为类型模板参数提供的所有模板参数的类型(跳过非类型模板参数和跳过模板模板参数)。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65199581

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档