如何将std::vector的内容打印到屏幕上?
实现以下操作符<<的解决方案也很好:
template<container C, class T, String delim = ", ", String open = "[", String close = "]">
std::ostream & operator<<(std::ostream & o, const C<T> & x)
{
// ... What can I write here?
}
以下是目前为止我所做的,没有单独的函数:
#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
#include <vector>
#include <sstream>
#include <cstdio>
using namespace std;
int main()
{
ifstream file("maze.txt");
if (file) {
vector<char> vec(istreambuf_iterator<char>(file), (istreambuf_iterator<char>()));
vector<char> path;
int x = 17;
char entrance = vec.at(16);
char firstsquare = vec.at(x);
if (entrance == 'S') {
path.push_back(entrance);
}
for (x = 17; isalpha(firstsquare); x++) {
path.push_back(firstsquare);
}
for (int i = 0; i < path.size(); i++) {
cout << path[i] << " ";
}
cout << endl;
return 0;
}
}
对于那些感兴趣的人:我写了一个通用的解决方案,它两全其美,更通用于任何类型的范围,并在非算术类型周围加上引号(适合于类似字符串的类型)。此外,这种方法不应该有任何ADL问题,也可以避免“意外”(因为它是根据具体情况明确添加的):
template <typename T>
inline constexpr bool is_string_type_v = std::is_convertible_v<const T&, std::string_view>;
template<class T>
struct range_out {
range_out(T& range) : r_(range) {
}
T& r_;
static_assert(!::is_string_type_v<T>, "strings and string-like types should use operator << directly");
};
template <typename T>
std::ostream& operator<< (std::ostream& out, range_out<T>& range) {
constexpr bool is_string_like = is_string_type_v<T::value_type>;
constexpr std::string_view sep{ is_string_like ? "', '" : ", " };
if (!range.r_.empty()) {
out << (is_string_like ? "['" : "[");
out << *range.r_.begin();
for (auto it = range.r_.begin() + 1; it != range.r_.end(); ++it) {
out << sep << *it;
}
out << (is_string_like ? "']" : "]");
}
else {
out << "[]";
}
return out;
}
现在它在任何范围都很容易使用:
std::cout << range_out{ my_vector };
类似字符串的检查留有改进的空间。
在我的解决方案中,我也有static_assert检查,以避免std::basic_string<>,但为了简单起见,我在这里省略了它。
for_each + lambda表达式怎么样:
#include <vector>
#include <algorithm>
// ...
std::vector<char> vec;
// ...
std::for_each(
vec.cbegin(),
vec.cend(),
[] (const char c) {std::cout << c << " ";}
);
// ...
当然,对于这个具体任务,基于范围的for是最优雅的解决方案,但它也提供了许多其他可能性。
解释
for_each算法接受一个输入范围和一个可调用对象,在范围的每个元素上调用该对象。输入范围由两个迭代器定义。可调用对象可以是一个函数、一个函数指针、一个重载()操作符的类的对象,或者在本例中是一个lambda表达式。此表达式的形参与vector中元素的类型匹配。
这个实现的美妙之处在于lambda表达式的强大功能——您可以使用这种方法做更多的事情,而不仅仅是打印向量。
对于想要没有循环的一行程序的人:
我不敢相信没有人知道这一点,但也许是因为更像c的方法。不管怎样,在没有循环的情况下,假设std::vector<char>是空终止的,在一行程序中是完全安全的:
std::vector<char> test { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\0' };
std::cout << test.data() << std::endl;
但为了安全起见,我会把它包装在ostream操作符中,就像@Zorawar建议的那样:
template <typename T>std::ostream& operator<< (std::ostream& out, std::vector<T>& v)
{
v.push_back('\0'); // safety-check!
out << v.data();
return out;
}
std::cout << test << std::endl; // will print 'Hello, world!'
我们可以通过使用printf来实现类似的行为:
fprintf(stdout, "%s\n", &test[0]); // will also print 'Hello, world!'
注意:
重载的ostream操作符需要接受非const的vector。这可能会使程序不安全或引入不可用的代码。此外,由于添加了空字符,可能会发生std::vector的重新分配。因此,使用带有迭代器的for循环可能会更快。