【发布时间】:2019-12-02 20:28:21
【问题描述】:
当一个元组中有多个没有成员的结构时,尝试在 GCC 上编译元组的比较会导致以下错误:
<source>: In function 'bool foo()':
<source>:120:16: error: request for member 'operator<' is ambiguous
120 | return a < b;
| ^
<source>:46:10: note: candidates are: 'bool N::operator<(const N&) const'
46 | bool operator<(const N &) const noexcept {
| ^~~~~~~~
<source>:46:10: note: 'bool N::operator<(const N&) const'
Compiler returned: 1
奇怪的是,当我将我在元组中使用的相同类型绑定在一起时,它会按预期工作。一个空结构也可以,不同类型的两个不行。
使用 clang 或 msvc 编译通过并产生预期结果。
这是正确的行为,还是 GCC/libstdc++ 错误?
演示
(Try it,先取消注释所需的测试用例)
#include <tuple>
struct A {
int value;
A(int value) : value(value) {}
bool operator==(const A &other) const noexcept {
return value == other.value;
}
bool operator!=(const A &other) const noexcept {
return value != other.value;
}
bool operator<(const A &other) const noexcept {
return value < other.value;
}
};
struct N {
bool operator==(const N &) const noexcept {
return true;
}
bool operator!=(const N &) const noexcept {
return false;
}
bool operator<(const N &) const noexcept {
return false;
}
};
struct M {
bool operator==(const M &) const noexcept {
return true;
}
bool operator!=(const M &) const noexcept {
return false;
}
bool operator<(const M &) const noexcept {
return false;
}
};
using AAKey = std::tuple<A, A>;
using ANAKey = std::tuple<A, N, A>;
using ANANKey = std::tuple<A, N, A, N>;
using ANAMKey = std::tuple<A, N, A, M>;
using NKey = std::tuple<N>;
using NNKey = std::tuple<N, N>;
using NMKey = std::tuple<N, M>;
bool foo() {
/* Works
AAKey a{0, 1};
AAKey b{0, 0};
//*/
/* Works
ANAKey a{0, N{}, 1};
ANAKey b{0, N{}, 0};
//*/
/* Fails
ANANKey a{0, N{}, 0, N{}};
ANANKey b{0, N{}, 1, N{}};
//*/
/* Fails
ANAMKey a{0, N{}, 0, M{}};
ANAMKey b{0, N{}, 1, M{}};
//*/
/* Works
NKey a{N{}};
NKey b{N{}};
//*/
/* Fails
NNKey a{N{}, N{}};
NNKey b{N{}, N{}};
//*/
/* Fails
NMKey a{N{}, M{}};
NMKey b{N{}, M{}};
//*/
// Tying ANANKey into tuple:
/* Works
A ax1{0}, ay1{0}, ax2{0}, ay2{1};
N nx1, ny1, nx2, ny2;
auto a = std::tie(ax1, nx1, ax2, nx2);
auto b = std::tie(ay1, ny1, ay2, ny2);
//*/
return a < b;
}
编辑
外部运算符重载确实有效(感谢@Turtlefight):
#include <tuple>
struct O {
friend bool operator==(const O &, const O &) noexcept {
return true;
}
friend bool operator!=(const O &, const O &) noexcept {
return false;
}
friend bool operator<(const O &, const O &) noexcept {
return false;
}
};
using OOKey = std::tuple<O, O>;
bool foo() {
OOKey a{O{}, O{}};
OOKey b{O{}, O{}};
return a < b;
}
【问题讨论】:
-
我会说这两个候选者是相同的功能这一事实很明显这是一个错误..
-
@LightnessRacesinOrbit 此外,
NMKey案例给出了两个不同的候选函数:bool N::operator<(const N&) const和bool M::operator<(const M&) const。 -
clang 上似乎不会发生这种情况。添加single member
int dummy;或使用externaloperator<overloads 似乎可以解决它。也许是编译器错误? -
@Turtlefight 确实外部重载工作,这是我可以使用的解决方法,感谢您的注意。