如何为 3D 矢量重载 ostream 运算符?
How to overload the ostream operator for 3D vector?
如何重载三维向量的流提取运算符?
vector<vector<vector<int>>> V(5, vector<int>>(3, vector<int>(2)))
我想出了以下回应。为什么以下代码不正确?
template <typename T>
ostream& operator<<(ostream &output, vector<T> &V) {
for(int i = 0; i < V.size(); i++)
for(int j = 0; j < V[i].size(); j++)
output << V[i][j] << " ";
return output;
}
谢谢!
首先,一般性评论:一般来说,用任何语言将 3D 向量表示为向量的向量都不是一个好主意 =39=].请不要传播此反模式。
存储多维向量的正确方法是将它们 "flattened" 保存在一维向量中。使用行主要顺序的 2D 示例:
这是你的 2D vector/array:
00 01 02
10 11 12
您可以按行优先顺序将其存储为:
00 01 02 10 11 12
并相应地索引元素。第 [i][j]
个元素位于平面一维数组中的 [i*colno +j]
处,其中 colno
是列数。但是请注意,如果您需要 "ragged arrays",即最后一个维度包含大小不等的行,则需要更多思考。
其次,您应该使用适当的库来处理此类多维 arrays/vectors。有很多,您可以查看例如the Eigen matrix library,它顺便提供了一个用于简单输出的重载 <<
运算符 :-)。
第三,您的代码仅在 2 个维度上迭代,并且没有正确传递 "vector-of-vectors-of-vector" 参数,正如其他人已经指出的那样。同样对于未来:将对象作为 const 引用传递给不会修改这些对象的函数,例如示例中的 V
。完成输出后 return ostream
对象。
但总的来说,请不要生气:您需要参加好的编程课程。编程难,C++编程更难。人们需要能得到的所有帮助。相信我,我知道我在说什么...:-)
你的j
循环的限制条件不正确,你需要j < V[i].size()
。
你说你的向量有三个维度,但你只是在两个维度上循环。
不清楚您传递给流运算符的确切类型,但我认为它类似于 std::vector<std::vector<std::vector<T>>>
并且由于您没有修改它,您应该通过 const 引用传递它。
我想你要找的是这样的:
template<typename T>
using Vector = std::vector<std::vector<std::vector<T>>>;
template <typename T>
std::ostream& operator<<(std::ostream& output, const Vector<T>& v) {
for(size_t i = 0; i < v.size(); i++) {
for(size_t j = 0; j < v[i].size(); j++) {
for(size_t k = 0; k < v[i][j].size(); k++)
output << v[i][j][k] << " ";
output << "\n";
}
output << "\n";
}
return output;
}
或者在 C++11 中:
#include <algorithm>
#include <iterator>
template <typename T>
std::ostream& operator<<(std::ostream& output, const Vector<T>& v) {
for(const auto& layer : v) {
for(const auto& row : layer) {
copy(row.begin(), row.end(), std::ostream_iterator<int>(output, " "));
output << "\n";
}
output << "\n";
}
return output;
}
我花了一点时间想出一个通用的解决方案,但这里是:
#include <iostream>
#include <vector>
template <typename T, typename _ = void>
struct is_vector : std::false_type
{
};
template <typename T>
struct is_vector< T, typename std::enable_if<std::is_same<T,std::vector< typename T::value_type,typename T::allocator_type >>::value
>::type>
: std::true_type
{
};
template<class T>
auto
emit(std::ostream& os, const T& t, size_t indent = 0)
-> std::enable_if_t<!is_vector<T>::value>
{
os << std::string(indent, ' ') << t;
}
template<class T, class A>
auto
emit(std::ostream& os, const std::vector<T, A>& v, size_t indent = 0)
-> std::enable_if_t<!is_vector<T>::value>
{
std::cout << std::string(indent, ' ') << "{ ";
const char* sep = "";
for (const auto& i : v) {
os << sep;
emit(os, i);
sep = ", ";
}
os << " }";
}
template<class T, class A>
auto
emit(std::ostream&os, const std::vector<T, A>& v, size_t indent = 0)
-> std::enable_if_t<is_vector<T>::value, void>
{
const auto prefix = std::string(indent, ' ');
std::cout << prefix << "{\n";
const char* sep = "";
for (const auto& i : v) {
os << sep;
emit(os, i, indent + 2);
sep = ",\n";
}
os << "\n" << prefix << "}";
}
template<class T, class A>
std::ostream& operator<<(std::ostream&os, const std::vector<T, A>& v)
{
emit(os, v);
return os;
}
using VI = std::vector<int>;
using VVI = std::vector<VI>;
using VVVI = std::vector<VVI>;
using namespace std;
int main(int argc, char **argv)
{
auto vi = VI { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
cout << "\n1 dimension:\n";
cout << vi << endl;
auto vvi = VVI {
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{10, 11, 12, 13, 14, 15, 16, 17, 18, 19 },
};
cout << "\n2 dimensions:\n";
cout << vvi << endl;
auto vvvi = VVVI {
{
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{10, 11, 12, 13, 14, 15, 16, 17, 18, 19 },
},
{
{20, 21, 22, 23, 24, 25, 26, 27, 28, 29 },
{30, 31, 32, 33, 34, 35, 36, 37, 38, 39 },
}
};
cout << "\n3 dimensions:\n";
cout << vvvi << endl;
return 0;
}
预期输出:
1 dimension:
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }
2 dimensions:
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }
}
3 dimensions:
{
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }
},
{
{ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 },
{ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39 }
}
}
Program ended with exit code: 0
如何重载三维向量的流提取运算符?
vector<vector<vector<int>>> V(5, vector<int>>(3, vector<int>(2)))
我想出了以下回应。为什么以下代码不正确?
template <typename T>
ostream& operator<<(ostream &output, vector<T> &V) {
for(int i = 0; i < V.size(); i++)
for(int j = 0; j < V[i].size(); j++)
output << V[i][j] << " ";
return output;
}
谢谢!
首先,一般性评论:一般来说,用任何语言将 3D 向量表示为向量的向量都不是一个好主意 =39=].请不要传播此反模式。
存储多维向量的正确方法是将它们 "flattened" 保存在一维向量中。使用行主要顺序的 2D 示例:
这是你的 2D vector/array:
00 01 02
10 11 12
您可以按行优先顺序将其存储为:
00 01 02 10 11 12
并相应地索引元素。第 [i][j]
个元素位于平面一维数组中的 [i*colno +j]
处,其中 colno
是列数。但是请注意,如果您需要 "ragged arrays",即最后一个维度包含大小不等的行,则需要更多思考。
其次,您应该使用适当的库来处理此类多维 arrays/vectors。有很多,您可以查看例如the Eigen matrix library,它顺便提供了一个用于简单输出的重载 <<
运算符 :-)。
第三,您的代码仅在 2 个维度上迭代,并且没有正确传递 "vector-of-vectors-of-vector" 参数,正如其他人已经指出的那样。同样对于未来:将对象作为 const 引用传递给不会修改这些对象的函数,例如示例中的 V
。完成输出后 return ostream
对象。
但总的来说,请不要生气:您需要参加好的编程课程。编程难,C++编程更难。人们需要能得到的所有帮助。相信我,我知道我在说什么...:-)
你的j
循环的限制条件不正确,你需要j < V[i].size()
。
你说你的向量有三个维度,但你只是在两个维度上循环。
不清楚您传递给流运算符的确切类型,但我认为它类似于 std::vector<std::vector<std::vector<T>>>
并且由于您没有修改它,您应该通过 const 引用传递它。
我想你要找的是这样的:
template<typename T>
using Vector = std::vector<std::vector<std::vector<T>>>;
template <typename T>
std::ostream& operator<<(std::ostream& output, const Vector<T>& v) {
for(size_t i = 0; i < v.size(); i++) {
for(size_t j = 0; j < v[i].size(); j++) {
for(size_t k = 0; k < v[i][j].size(); k++)
output << v[i][j][k] << " ";
output << "\n";
}
output << "\n";
}
return output;
}
或者在 C++11 中:
#include <algorithm>
#include <iterator>
template <typename T>
std::ostream& operator<<(std::ostream& output, const Vector<T>& v) {
for(const auto& layer : v) {
for(const auto& row : layer) {
copy(row.begin(), row.end(), std::ostream_iterator<int>(output, " "));
output << "\n";
}
output << "\n";
}
return output;
}
我花了一点时间想出一个通用的解决方案,但这里是:
#include <iostream>
#include <vector>
template <typename T, typename _ = void>
struct is_vector : std::false_type
{
};
template <typename T>
struct is_vector< T, typename std::enable_if<std::is_same<T,std::vector< typename T::value_type,typename T::allocator_type >>::value
>::type>
: std::true_type
{
};
template<class T>
auto
emit(std::ostream& os, const T& t, size_t indent = 0)
-> std::enable_if_t<!is_vector<T>::value>
{
os << std::string(indent, ' ') << t;
}
template<class T, class A>
auto
emit(std::ostream& os, const std::vector<T, A>& v, size_t indent = 0)
-> std::enable_if_t<!is_vector<T>::value>
{
std::cout << std::string(indent, ' ') << "{ ";
const char* sep = "";
for (const auto& i : v) {
os << sep;
emit(os, i);
sep = ", ";
}
os << " }";
}
template<class T, class A>
auto
emit(std::ostream&os, const std::vector<T, A>& v, size_t indent = 0)
-> std::enable_if_t<is_vector<T>::value, void>
{
const auto prefix = std::string(indent, ' ');
std::cout << prefix << "{\n";
const char* sep = "";
for (const auto& i : v) {
os << sep;
emit(os, i, indent + 2);
sep = ",\n";
}
os << "\n" << prefix << "}";
}
template<class T, class A>
std::ostream& operator<<(std::ostream&os, const std::vector<T, A>& v)
{
emit(os, v);
return os;
}
using VI = std::vector<int>;
using VVI = std::vector<VI>;
using VVVI = std::vector<VVI>;
using namespace std;
int main(int argc, char **argv)
{
auto vi = VI { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
cout << "\n1 dimension:\n";
cout << vi << endl;
auto vvi = VVI {
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{10, 11, 12, 13, 14, 15, 16, 17, 18, 19 },
};
cout << "\n2 dimensions:\n";
cout << vvi << endl;
auto vvvi = VVVI {
{
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{10, 11, 12, 13, 14, 15, 16, 17, 18, 19 },
},
{
{20, 21, 22, 23, 24, 25, 26, 27, 28, 29 },
{30, 31, 32, 33, 34, 35, 36, 37, 38, 39 },
}
};
cout << "\n3 dimensions:\n";
cout << vvvi << endl;
return 0;
}
预期输出:
1 dimension:
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }
2 dimensions:
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }
}
3 dimensions:
{
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }
},
{
{ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 },
{ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39 }
}
}
Program ended with exit code: 0