gpt4 book ai didi

c++ - std::tuple 与多个空成员的比较不会在 GCC 上编译

转载 作者:太空狗 更新时间:2023-10-29 21:31:48 27 4
gpt4 key购买 nike

当元组中有多个没有成员的结构时,尝试在 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

奇怪的是,当我绑定(bind)元组中使用的相同类型时,它会按预期工作。一个空结构也可以,两个不同类型的就不行。

使用 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;
}

最佳答案

这显然是一个错误,因为标准不允许比较无效。

原因更有趣。 libstdc++ 的元组以 tuple<N> 的方式进行 EBO实际上源自N如果N是一个空类。当你做 a < b我们需要对 operator< 进行非成员和成员查找.非成员查找找到 tupleoperator<正如预期的那样。

但是,此成员查找找到了 operator<在两个不同的基地,所以 [class.member.lookup]p6-7此查找会产生一个无效集,并且当场格式不正确。

Clang 似乎通过抑制成员查找中的错误来接受此代码,但我目前在标准中没有看到任何允许此行为的内容。

关于c++ - std::tuple 与多个空成员的比较不会在 GCC 上编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57187077/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com