gcc和c ++ 17的重载解析失败 [英] Overload resolution fails for gcc and 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 #define
ing 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
推荐答案
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屋!