假设我有一个枚举类:
enum class PType : int
{
Parallel = 0,
AntiParallel = 1,
BiParallel = 2,
NotParallel = 3
};
我现在想创建两个运算符
bool operator==(PType lhs, PType&& rhs)
bool operator==(PType&& lhs, PType rhs)
这样我就可以找出我的右值引用放在 == 的哪一侧。
不幸的是我遇到了编译错误
error C2593: 'operator ==' is ambiguous
在 VisualStudio 中,因为编译器会自动生成以下运算符:
bool operator==(const PType lhs, const PType rhs);
为了它。尝试用
删除它bool operator==(const PType lhs, const PType rhs) = delete;
不会导致该行出现编译错误,但之后我仍然收到“不明确”错误。
关于如何使这项工作有任何想法吗?
编辑: 我知道如何使用常规类来做到这一点,但我仍然想弄清楚为什么编译器会产生错误。我知道代码很粗略,风格不好,可能会导致许多人提到的错误。 无论如何,我认为这种类型的东西可以工作,所以我尝试了并且我认为如果我只能让“= delete”工作,它仍然可以工作。 所以现在我出于纯粹的学术兴趣问这个问题,因为我想了解更多关于编译器的信息,以及为什么当我删除函数时编译器没有报告错误,但几行之后又提示说据称删除的函数被认为是重载候选者。
我之所以要区分右值引用的位置,是因为我知道变量在 == 的哪一侧,以及可以在哪一侧找到像 PType::BiParallel 这样的比较值。这样做的原因是,与 PType::BiParallel 相比,包含 Parallel 或 AntiParallel 的变量应该返回 true,因为我只想知道我们是否有某种并行性。另一方面,如果变量包含 BiParallel 并与 PType::Parallel 或 PType::AntiParallel 进行比较,则两个比较都应该是假的,因为你不能说哪个是真的。 同样,我知道这是不好的风格,但我发现编译器接受“= delete”的原因在学术上很有趣。
最佳答案
我已经为这个问题写了另一个答案,但 OP 指出我的答案不正确。仔细想想,我认为 OP 试图做的事情根本不可能。
如 C++17 [over.built]/16 中所述,在重载解析期间,将生成带有签名的内置候选
bool operator==(PType, PType);
如果选择内置候选项,则 ==
的内置语义将适用。
现在,可以定义您自己的operator==
,但除非您声明一个具有与内置候选完全相同的签名,否则内置- in candidate 仍然会生成。因此,在过载解决时,内置候选者要么获胜(由于完全匹配),要么与某些用户声明的过载相关联,从而导致歧义。
如果您使用内置候选的确切签名声明自己的operator==
,则不会生成内置候选([over.match.oper]/(3.3 .4)).如果您愿意,您可以删除它:
bool operator==(PType, PType) = delete;
但是,删除的函数仍然参与重载决策(除非它是默认的移动构造函数或移动赋值运算符)。因此,这并不能解决问题:使用额外的重载,例如
bool operator==(PType&&, PType);
存在歧义的可能性,只有在参数类型实际已知时才会出现这种歧义。这就是为什么在您实际尝试使用 ==
之前不会出现编译错误的原因。
您真正想要的是某种方法来防止内置候选函数或具有相同签名的另一个函数完全不被重载决策考虑。如果您可以这样做,那么您可以强制根据重载集中的值类别选择重载,如下所示:
bool operator==(const PType& lhs, const PType& rhs);
bool operator==(const PType& lhs, PType&& rhs);
bool operator==(PType&& lhs, const PType& rhs);
bool operator==(PType&& lhs, PType&& rhs);
但据我所知,没有办法做到这一点,所以 OP 想要的似乎是不可能的。
关于c++ - 删除全局隐式函数 - 避免模棱两可的运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59180731/