【问题标题】:How to overload the ostream operator for 3D vector?如何为 3D 矢量重载 ostream 运算符?
【发布时间】:2015-05-23 14:39:39
【问题描述】:

如何重载三维向量的流提取操作符?

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;
}

谢谢!

【问题讨论】:

  • 缺少 return 语句是您的代码的一个问题。缺少对问题的描述是您的问题之一。
  • 什么是Vector? (大写 V)
  • @RichardHodges 一个疯狂的猜测说它是template&lt;typename T&gt; using Vector = vector&lt;vector&lt;vector&lt;T&gt;&gt;&gt;; ;) 或者它应该是这样的。
  • @vsoftco 假设我已经发布了一个通用矢量打印作为答案。

标签: c++ vector operator-overloading


【解决方案1】:

首先,一般性说明:通常不是一个好主意将 3D 向量表示为向量的向量在任何语言中。请不要传播此反模式。

存储多维向量的正确方法是将它们“展平”在一维向量中。使用行主要顺序的 2D 示例:

这是你的二维向量/数组:

00 01 02
10 11 12

您可以将其以行优先顺序存储为:

00 01 02 10 11 12

并相应地索引元素。 [i][j]-th 元素位于平面一维数组中的[i*colno +j],其中colno 是列数。但是请注意,如果您需要“参差不齐的数组”,即最后一个维度包含大小不等的行,则需要进行更多思考。

其次,您应该使用适当的库来处理此类多维数组/向量。有很多,您可以查看例如the Eigen matrix library,它顺便提供了一个重载的&lt;&lt; 运算符用于简单的输出:-)。

第三,正如其他人已经指出的那样,您的代码仅在二维上进行迭代,并且没有正确传递“vector-of-vectors-of-vector”参数。也适用于未来:将对象作为 const 引用传递给不会修改这些对象的函数,例如您的示例中的 V。完成输出后返回 ostream 对象。

但总的来说,请不要冒犯:您需要参加优秀的编程课程。编程难,C++编程更难。一个人需要所有能得到的帮助。相信我,我知道我在说什么...... :-)

【讨论】:

    【解决方案2】:

    您的j 循环的限制条件不正确,您需要j &lt; V[i].size()

    您说您的向量具有三个维度,但您只是在两个维度上循环。

    目前尚不清楚您传递给流操作符的确切类型,但我认为它类似于std::vector&lt;std::vector&lt;std::vector&lt;T&gt;&gt;&gt;,并且由于您没有修改它,因此您应该通过 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;
    }
    

    【讨论】:

      【解决方案3】:

      我花了一点时间才想出一个通用的解决方案,但这里是:

      #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
      

      【讨论】:

      • 这是一个不错的方法!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-10
      • 2021-01-20
      • 2020-07-16
      • 2012-04-13
      • 2018-12-04
      • 2011-12-17
      相关资源
      最近更新 更多