如何将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;
}
}
如果boost是一个选项,那么你可以使用boost::algorithm::join。例如,打印std::string的向量:
#include <boost/algorithm/string/join.hpp>
std::vector<std::string> vs { "some", "string", "vector" };
std::cout << boost::algorithm::join(vs, " | ") << '\n';
对于其他类型的向量,首先需要转换为字符串
#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>
#include <boost/algorithm/string/join.hpp>
#include <boost/range/adaptor/transformed.hpp>
int main()
{
using boost::adaptors::transformed;
using boost::algorithm::join;
// Generate the vector
std::vector<int> vi(10);
std::iota(vi.begin(), vi.end(), -3);
// Print out the vector
std::cout << join(vi |
transformed(static_cast<std::string(*)(int)>(std::to_string)),
", ")
<< '\n';
}
Godbolt演示
一个更简单的方法是使用标准复制算法:
#include <iostream>
#include <algorithm> // for copy
#include <iterator> // for ostream_iterator
#include <vector>
int main() {
/* Set up vector to hold chars a-z */
std::vector<char> path;
for (int ch = 'a'; ch <= 'z'; ++ch)
path.push_back(ch);
/* Print path vector to console */
std::copy(path.begin(), path.end(), std::ostream_iterator<char>(std::cout, " "));
return 0;
}
ostream_iterator被称为迭代器适配器。它被模板化在要打印到流的类型上(在本例中为char)。Cout(又名控制台输出)是我们想要写入的流,空格字符(" ")是我们想要打印在存储在vector中的每个元素之间的内容。
这个标准算法非常强大,其他算法也是如此。标准库提供的强大功能和灵活性使它如此出色。想象一下:您可以用一行代码将一个向量打印到控制台。您不必处理分隔符的特殊情况。您不需要担心for循环。标准库为您完成了这一切。
对于那些感兴趣的人:我写了一个通用的解决方案,它两全其美,更通用于任何类型的范围,并在非算术类型周围加上引号(适合于类似字符串的类型)。此外,这种方法不应该有任何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<>,但为了简单起见,我在这里省略了它。
使用std::copy,但没有额外的尾随分隔符
使用std::copy的替代/修改方法(最初在@JoshuaKravtiz answer中使用),但没有在最后一个元素后面包含额外的尾随分隔符:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
template <typename T>
void print_contents(const std::vector<T>& v, const char * const separator = " ")
{
if(!v.empty())
{
std::copy(v.begin(),
--v.end(),
std::ostream_iterator<T>(std::cout, separator));
std::cout << v.back() << "\n";
}
}
// example usage
int main() {
std::vector<int> v{1, 2, 3, 4};
print_contents(v); // '1 2 3 4'
print_contents(v, ":"); // '1:2:3:4'
v = {};
print_contents(v); // ... no std::cout
v = {1};
print_contents(v); // '1'
return 0;
}
用于自定义POD类型容器的示例:
// includes and 'print_contents(...)' as above ...
class Foo
{
int i;
friend std::ostream& operator<<(std::ostream& out, const Foo& obj);
public:
Foo(const int i) : i(i) {}
};
std::ostream& operator<<(std::ostream& out, const Foo& obj)
{
return out << "foo_" << obj.i;
}
int main() {
std::vector<Foo> v{1, 2, 3, 4};
print_contents(v); // 'foo_1 foo_2 foo_3 foo_4'
print_contents(v, ":"); // 'foo_1:foo_2:foo_3:foo_4'
v = {};
print_contents(v); // ... no std::cout
v = {1};
print_contents(v); // 'foo_1'
return 0;
}