【问题标题】:C++ cout auto separatorC++ cout 自动分隔符
【发布时间】:2015-05-06 09:54:05
【问题描述】:

我想知道std::cout 是否有办法自动在打印的序列之间插入一些预定义的值。

例如:

std::cout << 2 << 3 << 33 << 45 << std::endl;

输出

233345

我希望它输出

2 3 33 45

我知道,这很容易:

std::cout << 2 << " " << 3 <<  " " << 33 <<  " " << 45 << std::endl;

但我想知道是否有办法自动执行此操作,例如:

std::cout << set_some_separator(" ") << 2 << 3 << 33 << 45 << std::endl;

有人知道这样的事情是可能的吗?

【问题讨论】:

  • 我猜你可以从 cout 派生并重载
  • 您可以重载运算符 en.cppreference.com/w/cpp/language/operators
  • @Laykker 但我们不能重载原始数据类型,我们只能重载类或枚举,所以我认为不可能像 ostreamObj &lt;&lt; 2&lt;&lt;3;
  • 是的 @WojciechFrohmberg - 我的意思是从 std::ostream 派生。另一种选择是定义一个宏 #define SEPARATE( x ) x
  • @Jimmy 在您尝试复制构建基本流之前,这是个好主意;)

标签: c++


【解决方案1】:

好吧,我被打败了。无论如何我都会发布这个。

编辑:好吧,在阅读了 Nim 的回答后,我的 确实 实现了 OP 希望的确切语法。

#include <iostream>
#include <algorithm>

struct with_separator {
    with_separator(std::string sep)
    : sep(std::move(sep)) {}

    std::string sep;
};

struct separated_stream {
    separated_stream(std::ostream &stream, std::string sep)
    : _stream(stream), _sep(std::move(sep)), _first(true) {}

    template <class Rhs>
    separated_stream &operator << (Rhs &&rhs) {
        if(_first)
            _first = false;
        else
            _stream << _sep;

        _stream << std::forward<Rhs>(rhs);
        return *this;
    }

    separated_stream &operator << (std::ostream &(*manip)(std::ostream&)) {
        manip(_stream);
        return *this;
    }

    private:
    std::ostream &_stream;
    std::string _sep;
    bool _first;
};

separated_stream operator << (std::ostream &stream, with_separator wsep) {
    return separated_stream(stream, std::move(wsep.sep));
}

int main()
{
    std::cout << with_separator(", ") << 1 << 2 << 3 << std::endl;
}

输出:

1, 2, 3

【讨论】:

  • 不好意思问这个小问题,但我能说_sep(std::move(sep))“抢”了参数传递的std::string,然后把它留给类本身吗?跨度>
  • @user2018675 绝对!但请注意,所述字符串是函数的本地字符串,因为它是按值传递的:)
  • 不幸的是,这在将流转发到其他采用 ostream& 的函数时不起作用,因为 operator
  • @JonWatte 是的,事实上separated_stream 根本不是std::ostream:我在这里选择了最简单的方法来实现纯语法技巧。但是从std::basic_ostream继承并添加所需的接口应该是可行的。
【解决方案2】:

简单的答案是否定的,但是,您可以自己动手...

#include <iostream>
#include <sstream>

using namespace std;

struct set_some_separator{
    set_some_separator(const char* sep) : _sep(sep)
    { };

    template <typename T>
    set_some_separator& operator<<(const T& v)
    {
        _str << v << _sep;
        return *this;
    }

    friend
    ostream& operator<<(ostream& os, const set_some_separator& s)
    { return os << s._str.str(); }

    const char* _sep;
    ostringstream _str;
};

int main()
{
    cout << (set_some_separator(" ") << 2 << 3 << 33 << 45) << endl;
}

好吧,cout 的格式略有不同,嘿嘿...

【讨论】:

  • 在操作符
【解决方案3】:

不完全一样,但是:

#include <array>
#include <iostream>
#include <iterator>

int main() {
    std::array<int, 3> data = { 1, 2, 3 };
    std::ostream_iterator<int> out(std::cout, " ");
    std::copy(data.begin(), data.end(), out);
    std::cout << '\n';
    return 0;
}

【讨论】:

  • 插入尾随空格,不是吗?
【解决方案4】:

如何使用 ostream_iterator

int main()
{
     std::vector<int> data {2,3,33,45};
     std::copy(std::begin(data), std::end(data),
               std::ostream_iterator(std::cout, " "));
     std::cout << "\n";
}

【讨论】:

    【解决方案5】:

    带有逗号运算符的 C++17 折叠表达式可以创建一个不错的单行:

    [](auto &&...xs){ ((std::cout << xs << ',') , ...); }(2,3,33,45);
    

    【讨论】:

      【解决方案6】:

      简单的解决方案,也许你可以调整它以使用&lt;&lt;

      template<typename T> 
      void myout(T value) 
      { 
         std::cout << value << std::endl; 
      } 
      
      template<typename First, typename ... Rest> 
      void myout(First first, Rest ... rest) 
      { 
         std::cout << first << " ";
         myout(rest...); 
      }
      
      
      myout('a',"Hello",1,2,3,22/7.0);
      

      【讨论】:

        【解决方案7】:

        如果您只是在寻找一种打印矢量的方法,其元素已正确分隔(并且末尾没有额外的分隔符),请尝试以下操作:

        #include <iostream>
        #include <vector>
        
        int main()
        {
          std::vector<int> v{1, 2, 3};
        
          auto it = v.begin();
          if (it != v.end())
          {
            std::cout << *it;
            ++it;
          }
        
          for (; it != v.end(); ++it)
          {
            std::cout << ", " << *it;
          }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-02-28
          • 2014-07-08
          • 1970-01-01
          • 2016-06-10
          • 2012-04-10
          • 1970-01-01
          • 2020-01-05
          • 1970-01-01
          相关资源
          最近更新 更多