如何合并代码完全相同的多个C++容器输出模板函数?
解决方案
你之前的两种写法报错分别是语法问题和重载匹配冲突问题,下面给出两种可直接运行的实现方案:
问题原因说明
- 第一种写法
template<typename C, typename T> ostream& operator<<(ostream& os, const C<T>& dt)报错是因为C属于模板模板参数,需要显式声明为模板参数,语法不正确 - 第二种写法
template<typename C> ostream& operator<< (ostream& os, const C& dt)泛化程度过高,会和所有类型的输出重载匹配,产生冲突
另外你当前代码里的pair的operator<<重载没有返回os,属于未定义行为,会导致运行异常,需要补上返回值。
方案1:兼容C++11及以上版本(SFINAE实现)
我们通过SFINAE限制重载只匹配「有迭代器、不是字符串、不是pair」的STL容器:
#include <type_traits> #include <iterator> // 辅助trait:判断类型是不是STL容器(排除string和pair) template <typename T> struct is_stl_container { private: template <typename U> static auto test(int) -> decltype(std::begin(std::declval<U>()), std::end(std::declval<U>()), std::true_type()); template <typename> static auto test(...) -> std::false_type; public: static constexpr bool value = decltype(test<T>(0))::value && !std::is_same<T, std::string>::value && !std::is_same<T, std::wstring>::value; }; // pair的输出重载,记得补返回os template <typename T, typename V> ostream& operator<<(ostream& os, const pair<T, V>& p) { os << "(" << p.first << "," << p.second << ")"; return os; } // 通用STL容器输出重载 template <typename C> typename std::enable_if<is_stl_container<C>::value, ostream&>::type operator<<(ostream& os, const C& dt) { os << "{"; if (!dt.empty()) { auto it = dt.begin(); os << *it; ++it; for (; it != dt.end(); ++it) { os << "," << *it; } } os << "}"; return os; }
这个实现可以自动适配vector、set、map、unordered_map、list等所有标准STL容器,同时不会和字符串、基本类型、pair的输出重载冲突,而且修复了你原来空容器调用preEnd--的越界问题。
方案2:C++20及以上版本(Concept实现,更简洁)
如果你使用C++20及以上标准,可以用Concept简化判断逻辑:
#include <concepts> template <typename T> concept StlContainer = requires(T t) { std::begin(t); std::end(t); } && !std::same_as<T, std::string> && !std::same_as<T, std::wstring>; // pair的输出重载同上 template <typename T, typename V> ostream& operator<<(ostream& os, const pair<T, V>& p) { os << "(" << p.first << "," << p.second << ")"; return os; } template <StlContainer C> ostream& operator<<(ostream& os, const C& dt) { os << "{"; if (!dt.empty()) { auto it = dt.begin(); os << *it; ++it; for (; it != dt.end(); ++it) { os << "," << *it; } } os << "}"; return os; }
替换完上面的代码,你原来的dbg宏不需要做任何修改,就可以正常输出所有STL容器类型的内容。
内容的提问来源于stack exchange,提问作者Jeff
相关产品推荐
相关产品推荐

