gcc和c++17的过载解析失败

  • 本文关键字:失败 c++17 gcc c++ gcc c++17
  • 更新时间 :
  • 英文 :


下面的代码无法使用gcc(9.2(和c++17进行编译。它确实可以与clang和MSVC一起工作,它也可以工作到c++14。发生了什么,谁是对的,有没有简单的解决方法?已决定使用#define来消除gcc的unordered_set过载,但我更喜欢"干净"的解决方案。

#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模式中,它实现了DRP0522对CWG150的分辨率,允许在匹配模板模板参数时忽略默认模板参数:

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

其他编译器(尚未(实现P0522,因此不认为泛型重载是可行的。

假设它是可行的,并且在C++17中函数模板的偏序规则下,两个第二自变量都不能推导到另一个(Container<T, Alloc>std::unordered_set<K, Hasher, Keyeq, Alloc>(,因此重载是不明确的。注释中提到的解决方案是使泛型重载更具泛型,从而可以将std::unordered_set<K, Hasher, Keyeq, Alloc>推导出它;例如:

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_setT = KTs = {Hasher, Keyeq, Alloc}(,因此过载可以被部分排序。

这应该在C++14和C++17以及更高版本中都有效。

相关内容

最新更新