11

あなたの意見では、C ++ 11でstd::cout使用std::ostream_iteratorするために印刷し、末尾のデリメータを印刷しないようにするための最もエレガントな方法は何ですか?

私が印刷しているオブジェクトには双方向イテレーターがありますが、ランダムアクセスイテレーターはありません。

std::list<double> x{1,2,3,4,5,6};
std::copy(x.begin(), std::prev(x.end()),
                std::ostream_iterator<int>(std::cout, ",") );
if ( x.size() != 0 )
  std::cout << *(--x.end()) << std::endl;
4

3 に答える 3

10

これが私のお気に入りの1つですが、使用していませんstd::ostream_iterator

#include <iterator>
#include <string>
#include <iosfwd>

template <class C>
auto
print(std::ostream& os, const C& c,
      const std::string& delim = std::string(", "),
      const std::string& open_brace = std::string("{"),
      const std::string& close_brace = std::string("}")
     ) -> decltype(std::begin(c), std::end(c), os)
{
    os << open_brace;
    auto i = std::begin(c);
    auto e = std::end(c);
    if (i != e)
    {
        os << *i;
        for (++i; i != e; ++i)
            os << delim << *i;
    }
    os << close_brace;
    return os;
}

#include <list>
#include <iostream>

int main()
{
    std::list<double> x{1,2,3,4,5,6};
    print(std::cout, x) << '\n';
}

{1, 2, 3, 4, 5, 6}

アップデート

オリバーは私を抵抗できない挑戦に導いてくれました。:-)

#include <iterator>
#include <string>
#include <iosfwd>

namespace my {

template <class C>
auto
print(std::ostream& os, const C& c,
      const std::string& delim = std::string(", "),
      const std::string& open_brace = std::string("{"),
      const std::string& close_brace = std::string("}")
     ) -> decltype(std::begin(c), std::end(c), os);

template <class C,
           typename std::enable_if
                    <
                       !std::is_same<C, std::string>::value,
                    bool>::type = false
         >
inline
auto
operator<< (std::ostream& os, const C& c) -> decltype(print(os, c))
{
    return print(os, c);
}

template <class C>
auto
print(std::ostream& os, const C& c,
      const std::string& delim,
      const std::string& open_brace,
      const std::string& close_brace
     ) -> decltype(std::begin(c), std::end(c), os)
{
    os << open_brace;
    auto i = std::begin(c);
    auto e = std::end(c);
    if (i != e)
    {
        os << *i;
        for (++i; i != e; ++i)
            os << delim << *i;
    }
    os << close_brace;
    return os;
}

}

#include <list>
#include <forward_list>
#include <iostream>

int main()
{
    std::forward_list<std::list<double>> x{{}, {3, 2, 1}, {1,2,3,4,5,6}};
    my::print(std::cout, x) << '\n';
}

{{}, {3, 2, 1}, {1, 2, 3, 4, 5, 6}}

完璧ではありませんが、楽しかったです。:-)カスタム区切り文字を伝播し、より忠実に中括弧を付けるより良い方法がおそらくあります。

于 2012-06-17T19:11:50.273 に答える
3

次の方法でカーソルを戻します。

std::cout << "\b";

次に、区切り文字を上書きします。

于 2013-01-03T23:09:51.243 に答える
2

C ++ 14-残念ながら、イン/アウトストリームが必要です:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
#include <list>

int main()
{
    std::list<double> x{1,2,3,4,5,6};
    std::stringstream sstr;
    std::transform(x.begin(), x.end(), std::ostream_iterator<std::string>(sstr), [&](auto c){
        return (sstr.rdbuf()->in_avail() ? "," : "") + std::to_string(c);
    });
    std::cout << sstr.str() << std::endl;
}

住む

C ++ 17以降、この問題を修正するostream_joinerがあります。

#include <algorithm>
#include <experimental/iterator>
#include <iostream>
#include <iterator>

int main()
{
    int i[] = {1, 2, 3, 4, 5};
    std::copy(std::begin(i),
              std::end(i),
              std::experimental::make_ostream_joiner(std::cout, ", "));
}

住む

于 2016-03-21T19:15:37.163 に答える