以下代码无法使用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模式下,它将DR P0522的分辨率实现为CWG 150,从而在与模板模板参数匹配时可以忽略默认模板参数:
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>
),因此重载是模棱两可的。在注释中作为mentioned的解决方案是使通用重载更加通用,以便可以推导std::unordered_set<K, Hasher, Keyeq, Alloc>
; 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}
),因此重载可以部分进行排序。这应该在C++ 14和C++ 17及更高版本中都可以使用。
关于c++ - gcc和c++ 17的重载解析失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60390894/