c++ شرح - "دائم" std::setw




setprecision (3)

هل هناك أي طريقة لضبط مناور 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;
}

بعد الجري ، أرى:

001 2 4 8 10 20 40 80 100

001 002 004 008 010 020 040 080 100

أي كل setw يحمل مكانه باستثناء setw / width الذي يجب تعيينه لكل إدخال. هل هناك طريقة أنيقة لاستخدام std::copy (أو أي شيء آخر) مع setw ؟ وبالتأكيد أنا لا أقصد إنشاء وظيفة أو وظيفة خاصة بكتابة الأشياء إلى std::cout .


Answers

حسنا ، هذا غير ممكن. أي طريقة لجعله الاتصال. .width كل مرة مرة أخرى. لكن يمكنك استخدام الدفعة ، بالطبع:

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

انها لا تخلق فضاء خاص بها ، لكنه يحدث وراء المشهد :)


نظرًا لأن setw width لا setw إلى إعداد دائم ، فإن أحد الحلول هو تحديد نوع يتجاوز operator<< ، مع تطبيق setw قبل القيمة. سيسمح هذا لـ ostream_iterator لهذا النوع بالعمل بـ std::copy كما هو موضح أدناه.

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

يمكنك تحديد: (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;
}

ثم يمكن تطبيقه بـ std::copy (أو a for loop):

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

الإخراج ( demo )

   1,   2,   4,   8,  16,  32,  64, 128, 256,
   1,   2,   4,   8,  16,  32,  64, 128, 256, 512,1024,2048,4096,

التطبيقات التي ليست راضية عن 256 حرفًا مختلفًا فقط لديها خيارات إما باستخدام أحرف عريضة (أكثر من 8 بتات) أو ترميز متغاير الطول (ترميز متعدد البتات في مصطلحات C ++) مثل UTF-8. تتطلب الأحرف العريضة عمومًا مساحة أكبر من ترميز بطول متغير ، ولكنها أسرع في المعالجة. عادةً ما تستخدم التطبيقات متعددة اللغات التي تعمل بكميات كبيرة من النص أحرفًا كبيرة عند معالجة النص ، ولكن يتم تحويله إلى UTF-8 عند تخزينه على القرص.

والفرق الوحيد بين string و wstring هو نوع بيانات الأحرف التي يتم تخزينها. يخزن سلسلة char s الذي يكون حجمه مضمونًا على الأقل 8 بت ، بحيث يمكنك استخدام سلاسل لمعالجة مثل ASCII أو ISO-8859-15 أو نص UTF-8. المعيار لا يقول شيئا عن مجموعة الأحرف أو الترميز.

عمليا ، يستخدم كل مترجم مجموعة أحرف تتوافق أول 128 حرفًا مع ASCII. هذا هو الحال أيضًا مع المترجمين الذين يستخدمون ترميز UTF-8. الشيء المهم الذي يجب أن تكون على دراية به عند استخدام السلاسل النصية في UTF-8 أو بعض ترميزات أخرى متغيرة الطول ، هي أن الفهارس والأطوال تقاس بالبايتات وليس بالأحرف.

نوع البيانات من wstring هو wchar_t ، الذي لم يتم تعريف حجمه في المعيار ، إلا أنه يجب أن يكون على الأقل بحجم char ، عادةً 16 بت أو 32 بت. يمكن استخدام wstring لتجهيز النص في ترميز الأحرف الكبيرة المحدد للتنفيذ. نظرًا لأن التشفير لم يتم تعريفه في المعيار ، فإنه ليس من السهل التحويل بين السلاسل والأوتار. لا يمكن للمرء أن يفترض أن يكون هناك ترميز ذو طول ثابت.

إذا لم تكن بحاجة إلى دعم متعدد اللغات ، فقد تكون بخير باستخدام السلاسل العادية فقط. من ناحية أخرى ، إذا كنت تكتب تطبيقًا رسوميًا ، فغالبًا ما تكون واجهة برمجة التطبيقات تدعم الأحرف العريضة فقط. ثم ربما تريد استخدام نفس الأحرف الواسعة عند معالجة النص. ضع في اعتبارك أن UTF-16 عبارة عن ترميز بطول متغير ، مما يعني أنه لا يمكنك افتراض length() لإرجاع عدد الأحرف. إذا كانت واجهة برمجة التطبيقات تستخدم ترميزًا بطول ثابت ، مثل UCS-2 ، فستصبح المعالجة سهلة. من الصعب إجراء التحويل بين الأحرف العريضة و UTF-8 بطريقة محمولة ، ولكن مرة أخرى ، قد تدعم واجهة برمجة التطبيقات لواجهة المستخدم التحويل.







c++ templates setw