gcc和c ++ 17的重载解析失败 [英] Overload resolution fails for gcc and c++17

查看:70
本文介绍了gcc和c ++ 17的重载解析失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码无法使用gcc(9.2)和c ++ 17进行编译.它确实适用于clang和MSVC,也适用于c ++ 14.这是怎么回事,谁是对的,并且有一个简单的解决方法?借助 #define 将gcc的 unordered_set 重载消除了,但我希望使用干净"的解决方案.

The code below fails to compile with gcc (9.2) and c++17. It does work with clang and MSVC, it also worked up to c++14. What's going on, who is right and is there an easy workaround? Resorted to #defineing the unordered_set overload away for gcc but I'd prefer a 'clean' solution.

#include <unordered_set>
#include <iostream>

struct Stream
{};

template <typename T, typename Alloc, template<typename, typename> class Container>
Stream & operator<< (Stream &stream, const Container<T, Alloc>& container)
{
  std::cout << "container" << std::endl;
  return stream;
}

template <class K, class Hasher, class Keyeq, class Alloc>
Stream & operator<< (Stream &stream, const std::unordered_set<K, Hasher, Keyeq, Alloc> & container)
{
  std::cout << "unordered_set" << std::endl;
  return stream;
}

int main()
{
    Stream t;
    std::unordered_set<int> set;
    t << set;

    return 0;
}

结果:

<source>: In function 'int main()':    
<source>:25:7: error: ambiguous overload for 'operator<<' (operand types are 'Stream' and 'std::unordered_set<int>')    
   25 |     t << set;    
      |     ~ ^~ ~~~    
      |     |    |    
      |     |    std::unordered_set<int>    
      |     Stream    
<source>:8:10: note: candidate: 'Stream& operator<<(Stream&, const Container<T, Alloc>&) [with T = int; Alloc = std::hash<int>; Container = std::unordered_set]'    
    8 | Stream & operator<< (Stream &stream, const Container<T, Alloc>& container)    
      |          ^~~~~~~~    
<source>:15:10: note: candidate: 'Stream& operator<<(Stream&, const std::unordered_set<_Value1, _Hash1, _Pred1, _Alloc1>&) [with K = int; Hasher = std::hash<int>; Keyeq = std::equal_to<int>; Alloc = std::allocator<int>]'    
   15 | Stream & operator<< (Stream &stream, const std::unordered_set<K, Hasher, Keyeq, Alloc> & container)    
      |          ^~~~~~~~    
ASM generation compiler returned: 1    
<source>: In function 'int main()':    
<source>:25:7: error: ambiguous overload for 'operator<<' (operand types are 'Stream' and 'std::unordered_set<int>')    
   25 |     t << set;    
      |     ~ ^~ ~~~    
      |     |    |    
      |     |    std::unordered_set<int>    
      |     Stream    
<source>:8:10: note: candidate: 'Stream& operator<<(Stream&, const Container<T, Alloc>&) [with T = int; Alloc = std::hash<int>; Container = std::unordered_set]'    
    8 | Stream & operator<< (Stream &stream, const Container<T, Alloc>& container)    
      |          ^~~~~~~~    
<source>:15:10: note: candidate: 'Stream& operator<<(Stream&, const std::unordered_set<_Value1, _Hash1, _Pred1, _Alloc1>&) [with K = int; Hasher = std::hash<int>; Keyeq = std::equal_to<int>; Alloc = std::allocator<int>]'    
   15 | Stream & operator<< (Stream &stream, const std::unordered_set<K, Hasher, Keyeq, Alloc> & container)    
      |          ^~~~~~~~    
Execution build compiler returned: 1

https://godbolt.org/z/4dGu6L

推荐答案

gcc是正确的;这是因为在C ++ 17模式下,它实现了 DR P0522 CWG 150 的分辨率,允许使用默认模板参数匹配模板模板参数时忽略:

gcc is correct; this is because in C++17 mode it implements DR P0522's resolution to CWG 150, allowing default template parameters to be ignored when matching a template template parameter:

template <template <typename> class> void FD();
template <typename, typename = int> struct SD { /* ... */ };
FD<SD>();  // OK; error before this paper (CWG 150)

其他编译器尚未(尚未)实现P0522,因此认为通用重载不可行.

The other compilers do not (yet) implement P0522 and therefore do not see the generic overload as viable.

鉴于它是可行的,并且在C ++ 17中功能模板的部分排序规则下,两个相应的第二个参数都不能推导出另一个参数( Container< T,Alloc> vs. std :: unordered_set< K,Hasher,Keyeq,Alloc> ),因此重载是不明确的.注释中提到的 泛型重载,更通用,例如可以推断出 std :: unordered_set< K,Hasher,Keyeq,Alloc> 例如:

Given that it is viable, and under the rules for partial ordering of function templates in C++17, neither respective second argument can be deduced to the other (Container<T, Alloc> vs. std::unordered_set<K, Hasher, Keyeq, Alloc>) and so the overloads are ambiguous. The solution as mentioned in comments is to make the generic overload more generic, such that std::unordered_set<K, Hasher, Keyeq, Alloc> can be deduced to it; for example:

template <typename T, class... Ts, template<typename, class...> class Container>
Stream & operator<< (Stream &stream, const Container<T, Ts...>& container)

此处 std :: unordered_set< K,Hasher,Keyeq,Alloc> 推断为 Container< T,Ts ...> (其中 Container =std :: unordered_set T = K Ts = {Hasher,Keyeq,Alloc} ),因此可以对重载进行部分排序.

Here std::unordered_set<K, Hasher, Keyeq, Alloc> deduces to Container<T, Ts...> (with Container = std::unordered_set, T = K, Ts = {Hasher, Keyeq, Alloc}) and so the overloads can be partially ordered.

这应该在C ++ 14和C ++ 17及更高版本中都可以使用.

This should work in both C++14 and C++17, and later.

这篇关于gcc和c ++ 17的重载解析失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆