我使用以下代码打印通用C++容器并排除字符串(感谢这,所以回答)。
#include <iostream>
#include <vector>
template <typename T,
template <typename ELEM, typename ALLOC = std::allocator<ELEM>>
class Container>
std::ostream &operator<<(std::ostream &out, const Container<T> &container) {
out << "[";
bool first = true;
for (const auto &elem : container) {
if (first)
first = false;
else
out << ", ";
out << elem;
}
return out << "]";
}
int main() {
std::vector<std::vector<int>> v{{1, 2}, {3, 4}};
std::cout << v << "\n";
return 0;
},它正确地打印2d矢量。
[[1, 2], [3, 4]]也不会弄乱输出字符串。有清洁剂(概念为基础)吗?用C++20或C++23编写模板的方法?
发布于 2022-06-21 15:12:49
对于概念,您可能只需要容器/范围类型和丢弃类似字符串的类型,如下所示:
template <typename Container>
requires std::ranges::input_range<const Container>
&& (!std::convertible_to<const Container, std::string_view>)
std::ostream &operator<<(std::ostream &out, const Container& container)
{
out << "[";
const char* sep = "";
for (const auto &elem : container) {
out << sep << elem;
sep = ", ";
}
return out << "]";
}请注意,泛型模板至少应该包含一种用户类型。否则,它可能与将来用于std (或其他库)容器的operator<<冲突.
发布于 2022-06-21 15:16:53
更好的方法是使用{fmt}
#include <fmt/ranges.h>
#include <vector>
int main() {
std::vector<std::vector<int>> v{{1, 2}, {3, 4}};
fmt::print("{}\n", v); // prints [[1, 2], [3, 4]]
}will in C++23将以std::print的形式提供。
实际上,您必须处理字符串的两个问题:
"[")std::string)不需要包括在内您可以通过拒绝任何可转换为string_view的东西来消除这两种情况,而不是要求容器类型的特定形状,如C<T, A=?> (正如我所提到的,这也消除了std::array、std::span和std::map等东西)。这将允许您打印std::array和std::span,但是对于std::map,您必须处理.如何打印std::pair?然后如何打印一个std::pair,其中一个元素是范围?
那你把这个操作员超载放哪儿了?您不能将它放在std中(这是不允许的)。但是您也不能把它放在std中,因为否则真正的代码可能找不到它。
这是一个复杂的问题,这就是为什么最好让一个好的库(比如{fmt})来处理这个问题。
发布于 2022-06-21 15:49:53
您不应该在您不拥有的类型上重载操作符;您不应该拥有std容器。而且您只应该在关联的命名空间中重载操作符;不允许将重载注入std命名空间。
这意味着你不应该做你正在做的事情。
template<class T>
struct pretty_print {
T&& t;
};
template<class T>
pretty_print(T&&)->pretty_print<T>;
template<typename T>
concept printable = requires(T t) {
{ std::declval<std::ostream&>() << t } -> std::same_as<std::ostream&>;
};
template<printable T>
std::ostream& operator<<( std::ostream& os, pretty_print<T> pp ) {
return os << pp.t;
}这让你可以
void test1() {
int x=42;
std::cout << pretty_print{x} << "\n";
}对于任何可打印类型的x。然而,我们现在可以为不可打印的类型添加重载。
template<std::ranges::input_range T>
requires (not printable<T>)
std::ostream& operator<<( std::ostream& os, pretty_print<T> pp ) {
using std::begin; using std::end;
os << "[";
for (auto&& e : pp.t | std::ranges::views::take(1))
{
os << pretty_print{e};
}
for (auto&& e : pp.t | std::ranges::views::drop(1))
{
os << ", ";
os << pretty_print{e};
}
os << "]";
return os;
}
void test2() {
std::vector<int> v0 = {1,2,3};
std::cout << pretty_print{v0} << "\n";
std::vector<std::vector<int>> v1 = {{1},{1,2},{1,2,3}};
std::cout << pretty_print{v1} << "\n";
}现在,如果我们想支持对:
template<typename T>
concept pairlike = requires(T t) {
{ t.first };
{ t.second };
};
template<pairlike P>
std::ostream& operator<<( std::ostream& os, pretty_print<P> pp ) {
os << "{ ";
os << pretty_print{pp.t.first} << ", ";
os << pretty_print{pp.t.second} << " }";
return os;
}现在地图开始工作了。
void test3() {
std::map<int, int> m = {{0,1}, {1,2}, {2,4}};
std::cout << pretty_print{m} << "\n";
}实例化。
https://stackoverflow.com/questions/72702736
复制相似问题