如何将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;
}
}
这里是一个工作库,作为一个完整的工作程序,我刚刚把它组合在一起:
#include <set>
#include <vector>
#include <iostream>
#include <boost/utility/enable_if.hpp>
// Default delimiters
template <class C> struct Delims { static const char *delim[3]; };
template <class C> const char *Delims<C>::delim[3]={"[", ", ", "]"};
// Special delimiters for sets.
template <typename T> struct Delims< std::set<T> > { static const char *delim[3]; };
template <typename T> const char *Delims< std::set<T> >::delim[3]={"{", ", ", "}"};
template <class C> struct IsContainer { enum { value = false }; };
template <typename T> struct IsContainer< std::vector<T> > { enum { value = true }; };
template <typename T> struct IsContainer< std::set<T> > { enum { value = true }; };
template <class C>
typename boost::enable_if<IsContainer<C>, std::ostream&>::type
operator<<(std::ostream & o, const C & x)
{
o << Delims<C>::delim[0];
for (typename C::const_iterator i = x.begin(); i != x.end(); ++i)
{
if (i != x.begin()) o << Delims<C>::delim[1];
o << *i;
}
o << Delims<C>::delim[2];
return o;
}
template <typename T> struct IsChar { enum { value = false }; };
template <> struct IsChar<char> { enum { value = true }; };
template <typename T, int N>
typename boost::disable_if<IsChar<T>, std::ostream&>::type
operator<<(std::ostream & o, const T (&x)[N])
{
o << "[";
for (int i = 0; i != N; ++i)
{
if (i) o << ",";
o << x[i];
}
o << "]";
return o;
}
int main()
{
std::vector<int> i;
i.push_back(23);
i.push_back(34);
std::set<std::string> j;
j.insert("hello");
j.insert("world");
double k[] = { 1.1, 2.2, M_PI, -1.0/123.0 };
std::cout << i << "\n" << j << "\n" << k << "\n";
}
它目前只适用于vector和set,但通过扩展IsContainer专门化,可以使其适用于大多数容器。我没有过多地考虑这些代码是否最少,但我不能立即想到任何可以去掉的冗余代码。
编辑:只是为了好玩,我包含了一个处理数组的版本。我不得不排除字符数组,以避免进一步的歧义;使用wchar_t[]仍然会遇到麻烦。
你可以使用std::experimental::make_ostream_joiner:
#include <algorithm>
#include <experimental/iterator>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
int main()
{
std::vector<int> vi(12);
std::iota(vi.begin(), vi.end(), -5);
std::cout << "Int vector:\n";
std::copy(std::begin(vi),
std::end(vi),
std::experimental::make_ostream_joiner(std::cout, ", "));
std::cout <<"\nString vector:\n[";
std::vector<std::string> vs { "some", "string", "vector" };
std::copy(std::begin(vs),
std::end(vs),
std::experimental::make_ostream_joiner(std::cout, "] - ["));
std::cout << "]\n";
}
Godbolt演示
我将在这里添加另一个答案,因为我已经提出了与之前的方法不同的方法,那就是使用locale facet。
基本原理在这里
基本上你要做的是:
Create a class that derives from std::locale::facet. The slight downside is that you will need a compilation unit somewhere to hold its id. Let's call it MyPrettyVectorPrinter. You'd probably give it a better name, and also create ones for pair and map.
In your stream function, you check std::has_facet< MyPrettyVectorPrinter >
If that returns true, extract it with std::use_facet< MyPrettyVectorPrinter >( os.getloc() )
Your facet objects will have values for the delimiters and you can read them. If the facet isn't found, your print function (operator<<) provides default ones. Note you can do the same thing for reading a vector.
我喜欢这种方法,因为你可以使用默认打印,同时仍然能够使用自定义覆盖。
缺点是如果在多个项目中使用facet,则需要一个面向facet的库(因此不能仅仅是头文件),而且需要注意创建一个新的locale对象的开销。
我把这个作为一个新的解决方案来写,而不是修改我的另一个解决方案,因为我相信两种方法都是正确的,你可以选择。
一个更简单的方法是使用标准复制算法:
#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循环。标准库为您完成了这一切。