首页 > 解决方案 > 为`std::variant`重载&&会破坏不相关的`std::map`

问题描述

(这个问题最初是由Russian SO的另一位用户提出的。我在此处重新发布它,稍作改动以增加曝光度。)

考虑这段代码:

#include <map>
#include <variant>

void operator&&(std::variant<int>, std::variant<int>) {}

int main()
{
    std::map<int, int> vals;
    vals.find(42);
}

Clang(同时带有 libstdc++ 和 libc++)和 MSVC 编译它没有问题。

然而,GCC 11.1 和更新版本(包括主干)给出了这个:Run on gcc.godbolt.org

In file included from /opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/bits/move.h:57,
                 from /opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/bits/stl_pair.h:59,
                 from /opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/bits/stl_algobase.h:64,
                 from /opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/bits/stl_tree.h:63,
                 from /opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/map:60,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/type_traits: In instantiation of 'struct std::is_invocable<const std::less<int>&, const int&, const int&>':
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/type_traits:3001:73:   required from 'constexpr const bool std::is_invocable_v<const std::less<int>&, const int&, const int&>'
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/bits/stl_tree.h:770:8:   required from 'static const _Key& std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_S_key(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Const_Link_type) [with _Key = int; _Val = std::pair<const int, int>; _KeyOfValue = std::_Select1st<std::pair<const int, int> >; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, int> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Const_Link_type = const std::_Rb_tree_node<std::pair<const int, int> >*]'
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/bits/stl_tree.h:1903:36:   required from 'std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_lower_bound(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type, std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Base_ptr, const _Key&) [with _Key = int; _Val = std::pair<const int, int>; _KeyOfValue = std::_Select1st<std::pair<const int, int> >; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, int> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator = std::_Rb_tree<int, std::pair<const int, int>, std::_Select1st<std::pair<const int, int> >, std::less<int>, std::allocator<std::pair<const int, int> > >::iterator; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type = std::_Rb_tree_node<std::pair<const int, int> >*; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Base_ptr = std::_Rb_tree_node_base*]'
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/bits/stl_tree.h:2521:36:   required from 'std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::find(const _Key&) [with _Key = int; _Val = std::pair<const int, int>; _KeyOfValue = std::_Select1st<std::pair<const int, int> >; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, int> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator = std::_Rb_tree<int, std::pair<const int, int>, std::_Select1st<std::pair<const int, int> >, std::less<int>, std::allocator<std::pair<const int, int> > >::iterator]'
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/bits/stl_map.h:1170:25:   required from 'std::map<_Key, _Tp, _Compare, _Alloc>::iterator std::map<_Key, _Tp, _Compare, _Alloc>::find(const key_type&) [with _Key = int; _Tp = int; _Compare = std::less<int>; _Alloc = std::allocator<std::pair<const int, int> >; std::map<_Key, _Tp, _Compare, _Alloc>::iterator = std::_Rb_tree<int, std::pair<const int, int>, std::_Select1st<std::pair<const int, int> >, std::less<int>, std::allocator<std::pair<const int, int> > >::iterator; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = int]'
<source>:9:14:   required from here
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/type_traits:2942:7: error: ambiguous overload for 'operator&&' (operand types are 'std::true_type' {aka 'std::integral_constant<bool, true>'} and 'std::true_type' {aka 'std::integral_constant<bool, true>'})
 2942 |       static_assert((std::__is_complete_or_unbounded(
      |       ^~~~~~~~~~~~~
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/type_traits:2942:7: note: candidate: 'operator&&(std::integral_constant<bool, true>::value_type {aka bool}, std::integral_constant<bool, true>::value_type {aka bool})' (built-in)
<source>:4:6: note: candidate: 'void operator&&(std::variant<int>, std::variant<int>)'
    4 | void operator &&(std::variant<int>, std::variant<int>) {}
      |      ^~~~~~~~

这里发生了什么?


编辑:

我们的operator==重载对于名称查找应该是不可见的<variant>(除了 ADL,这里不涉及),所以这绝对是一个 GCC 错误。

@rustyx 发现GCC 错误 #51577,看起来非常相似。但还有更多,因为该错误是在 GCC 4.7.0 中引入的,而上面的代码仅在 11.1 和更高版本中中断。

标签: c++gcc

解决方案


推荐阅读