"永久"std :: setw

Mir*_*cek 30 c++ templates setw

有没有办法永久设置std::setw操纵器(或其功能width)?看这个:

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <iterator>

int main( void )
{
  int array[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256 };
  std::cout.fill( '0' );
  std::cout.flags( std::ios::hex );
  std::cout.width( 3 );

  std::copy( &array[0], &array[9], std::ostream_iterator<int>( std::cout, " " ) );

  std::cout << std::endl;

  for( int i = 0; i < 9; i++ )
  {
    std::cout.width( 3 );
    std::cout << array[i] << " ";
  }
  std::cout << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

跑完后,我看到:

001 2 4 8 10 20 40 80 100

001 002 004 008 010 020 040 080 100
Run Code Online (Sandbox Code Playgroud)

即每个操纵器都保持其位置,除了必须为每个条目设置的setw/ width.有没有优雅的方式如何使用std::copy(或其他东西)setw?优雅的我当然不是指创建自己的函子或函数来编写东西std::cout.

Joh*_*itb 19

嗯,这是不可能的.无法.width再次拨打电话.但是你当然可以使用boost:

#include <boost/function_output_iterator.hpp>
#include <boost/lambda/lambda.hpp>
#include <algorithm>
#include <iostream>
#include <iomanip>

int main() {
    using namespace boost::lambda;
    int a[] = { 1, 2, 3, 4 };
    std::copy(a, a + 4, 
        boost::make_function_output_iterator( 
              var(std::cout) << std::setw(3) << _1)
        );
}
Run Code Online (Sandbox Code Playgroud)

确实创建了自己的仿函数,但它发生在幕后:)


cha*_*pjc 12

由于setw并且width不会导致持久性设置,因此一种解决方案是定义一个覆盖的类型,在值之前operator<<应用setw.这将允许ostream_iterator该类型的功能std::copy如下所示.

int fieldWidth = 4;
std::copy(v.begin(), v.end(),
    std::ostream_iterator< FixedWidthVal<int,fieldWidth> >(std::cout, ","));
Run Code Online (Sandbox Code Playgroud)

可以定义:(1)FixedWidthVal与用于数据类型(参数模板类typename)和宽度(值),和(2)一个operator<<用于ostream和一个FixedWidthVal适用setw 于每个插入.

// FixedWidthVal.hpp
#include <iomanip>

template <typename T, int W>
struct FixedWidthVal
{
    FixedWidthVal(T v_) : v(v_) {}
    T v;
};

template <typename T, int W>
std::ostream& operator<< (std::ostream& ostr, const FixedWidthVal<T,W> &fwv)
{
    return ostr << std::setw(W) << fwv.v;
}
Run Code Online (Sandbox Code Playgroud)

然后它可以应用std::copy(或for循环):

// fixedWidthTest.cpp
#include <iostream>
#include <algorithm>
#include <iterator>
#include "FixedWidthVal.hpp"

int main () {
    // output array of values
    int array[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256 };

    std::copy(array,array+sizeof(array)/sizeof(int), 
        std::ostream_iterator< FixedWidthVal<int,4> >(std::cout, ","));

    std::cout << std::endl;

    // output values computed in loop
    std::ostream_iterator<FixedWidthVal<int, 4> > osi(std::cout, ",");
    for (int i=1; i<4097; i*=2)
        osi = i; // * and ++ not necessary

    std::cout << std::endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出(演示)

   1,   2,   4,   8,  16,  32,  64, 128, 256,
   1,   2,   4,   8,  16,  32,  64, 128, 256, 512,1024,2048,4096,
Run Code Online (Sandbox Code Playgroud)

  • @j_random_hacker好吧,我应该在信用到期时给予信任.我从[codereview question](http://codereview.stackexchange.com/q/18291/35254)采用了这种方法,只是添加了数据类型模板参数.方便功能的好建议. (3认同)
  • 非常好的设计,我认为适用于很多情况.如果宽度可以是运行时(而不是编译时)参数,那将是理想的,尽管我无法想到将这些信息"转换为"ostream_iterator`的好方法.你还可以提供一个方便函数`template <typename T,int W> with_width(T v){return FixedWidthVal <T>(v,width); 保存必须指定类型. (2认同)