c++ - gcc和c++ 17的重载解析失败

标签 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模式下,它将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_setT = KTs = {Hasher, Keyeq, Alloc}),因此重载可以部分进行排序。

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

关于c++ - gcc和c++ 17的重载解析失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60390894/

相关文章:

c++ - (GCC 错误?)隐式转换为派生类

c - 我的第一个 C 编译器是用 gcc 编译的。我使用哪个文件?

c++ - 折叠表达式与任意可调用?

c++ - "constexpr if"比 switch 语句好吗?

c++ - "else"DevC++ 之前的预期主表达式

c++ - Windows C++ API ListView 未显示

c++ - 如何在 std::map 中存储混合类型项目?

c# - C++ DLL LPCTSTR 到 C# 字符串

c++ - 在c++中的macOS Catalina上编译 header 和cpp文件的问题

c++ - flto 与 gcc7.2 崩溃