gpt4 book ai didi

c++ - << 运算符模板的实现//C++

转载 作者:行者123 更新时间:2023-12-03 21:08:10 30 4
gpt4 key购买 nike

我想在 C++ 中制作一个 << 运算符的模板,它会显示一个“范围”的对象(我的意思是任何对象,如:std::vector、std::set、std::map, std::deque)。我怎样才能做到这一点?我已经用谷歌搜索并查看文档几天了,但没有任何效果。我之前一直在做一些模板并且覆盖了一些运算符,但这些是在代表自定义 vector 类的某个类中。我似乎无法找到实现这一点的好方法,因为它与标准 cout 发生冲突。那么,在可以传递 vector 、集合、映射、双端队列作为参数和内部运算符的类内部,我该怎么做?我还希望此运算符返回对象的 begin() 和 end() 迭代器。现在我有这个代码:

template <typename T>
ostream& operator<<(ostream& os, T something)
{
os << something.begin() << something.end();
return os;
}

它并没有真正起作用,我认为有经验的 C++ 程序员可以解释我为什么。
提前感谢您对该问题的任何回答。

最佳答案

您的重载将匹配几乎所有导致 operator<< 的类型歧义的内容。已经重载了。
我怀疑您想在此处打印容器中的所有元素:os << something.begin() << something.end(); .这将不起作用,因为 begin()end()返回迭代器。你可以取消引用它们

if(something.begin() != something.end())
os << *something.begin() << *std::prev(something.end());
但你只会打印第一个和最后一个元素。这将打印所有这些:
for(const auto& v : something) os << v;
为了解决歧义问题,您可以使用模板模板参数并启用 operator<<您想要支持的容器的过载。
例子:
#include <deque>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <type_traits>
#include <vector>

// helper trait - add containers you'd like to support to the list
template <typename T> struct is_container : std::false_type {};
template <typename... Ts> struct is_container<std::vector<Ts...>> : std::true_type{};
template <typename... Ts> struct is_container<std::list<Ts...>> : std::true_type{};
template <typename... Ts> struct is_container<std::deque<Ts...>> : std::true_type{};
template <typename... Ts> struct is_container<std::map<Ts...>> : std::true_type{};

// C is the container template, like std::vector
// Ts... are the template parameters used to create the container.
template <template <typename...> class C, typename... Ts>
// only enable this for the containers you want to support
typename std::enable_if<is_container<C<Ts...>>::value, std::ostream&>::type
operator<<(std::ostream& os, const C<Ts...>& something) {
auto it = something.begin();
auto end = something.end();
if(it != end) {
os << *it;
for(++it; it != end; ++it) {
os << ',' << *it;
}
}
return os;
}
另一种方法是使其通用,但禁用已支持流的类型的重载。
#include <iostream>
#include <iterator>
#include <type_traits>

// A helper trait to check if the type already supports streaming to avoid adding
// an overload for std::string, std::filesystem::path etc.
template<typename T>
class is_streamable {
template<typename TT>
static auto test(int) ->
decltype( std::declval<std::ostream&>() << std::declval<TT>(), std::true_type() );

template<typename>
static auto test(...) -> std::false_type;

public:
static constexpr bool value = decltype(test<T>(0))::value;
};

template <typename T,
typename U = decltype(*std::begin(std::declval<T>())), // must have begin
typename V = decltype(*std::end(std::declval<T>())) // must have end
>
// Only enable the overload for types not already streamable
typename std::enable_if<not is_streamable<T>::value, std::ostream&>::type
operator<<(std::ostream& os, const T& something) {
auto it = std::begin(something);
auto end = std::end(something);
if(it != end) {
os << *it;
for(++it; it != end; ++it) {
os << ',' << *it;
}
}
return os;
}
注意:最后一个例子适用于 clang++MSVC但在 g++ 中编译失败(超过递归深度)。
对于带有 value_type 的容器这本身是不可流式传输的,例如 std::pair<const Key, T>std::map ,您需要添加单独的重载。这需要在上述任何模板之前声明:
template <typename Key, typename T>
std::ostream &operator<<(std::ostream &os, const std::pair<const Key, T>& p) {
return os << p.first << ',' << p.second;
}

关于c++ - << 运算符模板的实现//C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65534442/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com