c++ - 尝试为所有 std 容器打印重载运算符 << 时出错,为什么?

标签 c++ string templates compiler-errors c++17

我正在尝试构建一个 operator <<重载以打印所有标准库容器类型。到目前为止,重载运行良好,但是当我在通用程序中使用它时,当我尝试打印简单的 std::string 时,它会中断。 。事实上,这个程序:

#include <iostream>
#include <utility>
#include <vector>
#include <map>
#include <string>

// Helper Function to Print Test Containers (Vector and Map)
template <typename T, typename U>
inline std::ostream& operator<<(std::ostream& out, const std::pair<T, U>& p) {
    out << "[" << p.first << ", " << p.second << "]";
    return out;
} 

template <template <typename, typename...> class ContainerType, typename 
ValueType, typename... Args>
std::ostream& operator <<(std::ostream& os, const ContainerType<ValueType, Args...>& c) {
    for (const auto& v : c) {
        os << v << ' ';
    }
  return os;
}

int main()
 {
  std::vector <int> v = { 1,2,3 };
  std::cout << v;

  std::map <int,int> m = { { 1, 1} , { 2, 2 }, { 3, 3 } };
  std::cout << m;

  std::string s = "Test";
  std::cout << s;
 }

给我这个错误:

prove.cpp: In function ‘int main()’:
prove.cpp:32:13: error: ambiguous overload for ‘operator<<’ (operand types are ‘std::ostream’ {aka ‘std::basic_ostream<char>’} and ‘std::string’ {aka ‘std::__cxx11::basic_string<char>’})
   32 |   std::cout << s;
      |   ~~~~~~~~~ ^~ ~
      |        |       |
      |        |       std::string {aka std::__cxx11::basic_string<char>}
      |        std::ostream {aka std::basic_ostream<char>}
prove.cpp:16:15: note: candidate: ‘std::ostream& operator<<(std::ostream&, const ContainerType<ValueType, Args ...>&) [with ContainerType = std::__cxx11::basic_string; ValueType = char; Args = {std::char_traits<char>, std::allocator<char>}; std::ostream = std::basic_ostream<char>]’
   16 | std::ostream& operator <<(std::ostream& os, const ContainerType<ValueType, Args...>& c) {
      |               ^~~~~~~~
In file included from /usr/include/c++/9/string:55,
                 from /usr/include/c++/9/bits/locale_classes.h:40,
                 from /usr/include/c++/9/bits/ios_base.h:41,
                 from /usr/include/c++/9/ios:42,
                 from /usr/include/c++/9/ostream:38,
                 from /usr/include/c++/9/iostream:39,
                 from prove.cpp:1:
/usr/include/c++/9/bits/basic_string.h:6419:5: note: candidate: ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’
 6419 |     operator<<(basic_ostream<_CharT, _Traits>& __os,
      |     ^~~~~~~~

我认为问题是由于这个重载用于打印也很简单 std::string对象,但到目前为止我还没有找到任何合适的方法来解决这个问题。有什么帮助吗?谢谢。

最佳答案

您的operator<<重载可能匹配 operator<< 的类型过载已经定义。我建议您对此类类型禁用它:

#include <type_traits>

template <template <typename, typename...> class ContainerType,
          typename ValueType, typename... Args>
std::enable_if_t<!is_streamable_v<ContainerType<ValueType, Args...>>,
                 std::ostream&>
operator<<(std::ostream& os, const ContainerType<ValueType, Args...>& c) {
    for (const auto& v : c) {
        os << v << ' ';
    }
    return os;
}

enable_if_t线路使用SFINAE禁用已可流式传输的类型的功能。

类型特征 is_streamable_v上面使用的可能如下所示:

template<class T>
struct is_streamable {
    static std::false_type test(...);
    
    template<class U>
    static auto test(const U& u) -> decltype(std::declval<std::ostream&>() << u,
                                             std::true_type{});

    static constexpr bool value = decltype(test(std::declval<T>()))::value;
};

// helper variable template:
template<class T>
inline constexpr bool is_streamable_v = is_streamable<T>::value;

您的原始程序现在应该按预期工作:

int main() {
  std::vector <int> v = { 1,2,3 };
  std::cout << v;

  std::map <int,int> m = { { 1, 1} , { 2, 2 }, { 3, 3 } };
  std::cout << m;

  std::string s = "Test";
  std::cout << s;
} 

Demo

关于c++ - 尝试为所有 std 容器打印重载运算符 << 时出错,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73307166/

相关文章:

c++ rest sdk http_listener 作为网络服务器

c++ - 为什么在访问数组的越界元素时没有出现运行时错误?

c# - 字符串上的 ReferenceEquals

java - 将阿拉伯语存储在字符串中并使用 Java 将其插入数据库

替换出现在字符串末尾的文本

php - CodeIgniter - mysql while 循环

c++ - QT5:如何将一个样式表应用于不同的小部件?

c++ - 将指针连接到 boost::signals2

templates - 为什么在D中使用static?

c++ - 为什么模板仿函数作为值传递而不是转发引用