16 Şubat 2018 Cuma

Stream Manipulators

Giriş
Manipulators şu dosya içinde tanımlı
#include <iomanip>
Manipulators aslında metod çağrısı
stream sınıfları << operatörü ile metod çağırabiliyor. stream sınıflarının şöyle bir metodu var.
basic_ostream& operator<<(
  std::basic_ostream<CharT,Traits>& (*func)(std::basic_ostream<CharT,Traits>&) );
Örnekte f() metodunun çağrıldığı görülebilir.
#include <iostream>

using namespace std;

ostream& f(ostream& os) {
    return os << "hi";
}

int main() {
    cout << "hello " << f << endl;
    return 0;
}
Eğer bir gün kendi myendl metodumu yazmam gerekirse şöyle yaparım.
std::ostream & myendl(std::ostream &s) {
    s<<'\n';
    s.flush();
    return s;
}
std::boolalpha
true,false şeklindeki string'ler ile bool değişkenler arasında geçiş sağlar.

Okumak
Elimizde şöyle bir satır olsun.
Pie 3.14515 69 true
Şöyle değişkenler olsun.
double first, second;
std::string mainString;
bool truth;
Satırı okumak için  şöyle yaparız.
datafile >> mainString >> first >> second
         >> std::boolalpha >> truth; 
Yazmak
Şöyle yaparız.
std::cout std::boolalpha << truth;
Şöyle yaparız.
boolalpha (cout);
std::dec
std::hex gibi sayının tabanını değiştirir. Onluk tabanda okumak için şöyle yaparız
cin >> std::dec >>c;
std::endl
Açıklaması şöyle
endl is an output-only I/O manipulator, it may be called with an expression such as out << std::endl for any out of type std::basic_ostream.

Inserts a newline character into the output sequence os and flushes it as if by calling os.put(os.widen('\n')) followed by os.flush().
std::endl bir değişken değildir. Bir template function'dır ve imzası şöyledir.
template <class CharT, class Traits>
std::basic_ostream<CharT, Traits>& endl (std::basic_ostream<CharT, Traits>& os);
std::endl şuna denk gelir.
o.put(o.widen('\n'));
o.flush();
Template function'ların çalışmasının sebebi, std::ostream içinde şöyle metodun olmasıdır
std::ostream &operator<<(std::ostream &os, ostream &(*f)(ostream &os)) { 
  return f(*this);
}
Örnek
Eğer kendi template function metodumuzu yazmak istersek şöyle yaparız.
template< class CharT, class Traits >
std::basic_ostream<CharT, Traits>& foo (std::basic_ostream<CharT, Traits>& os) {
  return os << "foo!";
}
Template olmayan halini kullanmak istersek şöyle yaparız.
std::ostream& foo (std::ostream& os) {
   return os << "foo!");
}
Şöyle kullanırız.
cout << foo << endl;
std::fixed - sticky
Scientific gösterim yerine ondalıklı gösterimi kullanır. Şöyle yaparız.
cout<< std::fixed<< 0.0675 <<endl;
std::hex -sticky
std::hex çağrısı aslında stream'in bir bayrağının kaldırılması anlamına geliyor. Atanan bayrak std::ios_base::hex değişkeni. Metodun içi şöyle
std::ios_base& hex(std::ios_base& stream) {
    stream.setf(std::ios_base::hex, std::ios_base::basefield);
    return stream;
}
hex'ten herkes şikayetçi. Rakamın başına 0x koymuyor.
cout << std::hex << 255 << endl;       // output: FF
cout << std::hex << 135 << endl;       // output: 87
cout << std::hex << 11 << endl;        // output: b
char (signed veya unsigned) ile çalışmıyor. int'e cast etmek gerekiyor. Örnekte +k aslında (int)k anlamına geliyor.
#include <iostream>
using namespace std;

int main(void)
{
    unsigned char k = 0xd8;
    cout << "k = 0x" << hex << +k << endl;
}
Daha kolay olsun istersek şöyle yaparız.
cout << "a is " << hex << (int) a <<"; b is " << hex << (int) b << endl;
std::internal
Açıklaması şöyle
We need to add the std::internal flag to tell the stream to insert "internal padding" -- i.e., the padding should be inserted between the sign and the rest of the number.
padleme işlemi sign işareti ile sayı arasında gerçekleşir. Yani +001 gibi bir çıktı verir. Şöyle yaparız.
std::ostringstream oss;

oss << std::setfill('0');
oss << std::setw(3);
oss << std::internal;
oss << std::showpos;
oss << 1; 

std::cout << oss.str(); // Output: "+01"
std::lowercase
Örnek ver.

std::noshowpoint
Örnek ver.

std::noskip
Bu metod aslında stream manipulator sayılmasa da bu yazıya dahil etmek istedim. Tüm whitespace karakterleri okumak için şöyle yaparız.
std::noskipws(in); // read spaces as well as characters
std::nounitbuf
Örnek ver.

std::unitbuf
Her output işleminden sonra otomatik flush eder.
Örnek
Şöyle yaparız.
mystream << std::unitbuf;
Örnek
Şöyle yaparız.
std::cout << std::unitbuf;
std::uppercase
Örnek ver.

std::setbase
Şöyle kullanırız
std::cout << setbase(16) << 32;
std::setfill
Şöyle kullanırız
cout << hex
     <<   "a is " << setfill('0') << setw(2) << int(a)
Bu durumda çıktı şöyle olur
a is 00; b is ff
std::setprecision
Double sayının toplam kaç hane olarak string'e çevrileceğini belirtir.
cout << setprecision(3) << 12.3456 << endl;
Çıktı olarak 12.3 alırız.

std::setprecision sıfırları yazmaz. Şöyle yaparsak
cout << setprecision(2) << 0.999 << endl;` 
Çıktı olarak 1.0 yerine 1 alırız.

std::precision + std::fixed
Eğer fixed ile beraber kullanırsak, bu sefer toplam hane sayısı yerine noktadan sonra kaç hane istediğimizi belirtiriz.
cout << fixed (3) << setprecision(3) << 12.3456 << endl;
Çıktı olarak 12.346 alırız.

Şöyle yaparsak
cout << setprecision(2) << fixed << 0.999 << endl;
Çıktı olarak 1.00  alırız.

std::setw
Açıklaması şöyle
setw goes before the thing you're columnising, not afterwards. This is because the manipulator needs to start counting characters in order to make it work.

cout << endl << "Name : " << setw(25) << left;
Now the stream is set up to treat the next insertion (i.e your. cout << c) as columnar, left-aligned with width 25.
Yukarıdaki setfill örneği açıklayıcı. Şöyle yaparız.
void hexdump(std::string const& buf) {
    for (std::string::const_iterator it = buf.begin(), end = buf.end();
         it != end;
         ++it) {
  std::cout
    << std::setw(2)
    << std::hex
    << std::setfill('0')
    << (static_cast<int>(*it) & 0xff)
    << ' ';
  }
  std::cout << std::dec << std::endl;
}

std::noshowpoint
Örnek ver.

std::scientific
Bilimsel gösterimi kullanır. Çıktı olarak 1.73709e+006 gibi bir şey gösterir. Şöyle yaparız.
cout << std::scientific << 0.0675 << std::endl;

std::showpoint
showpoint'i fixed ve precision ile kullanmak mantıklı. Eğer sayının küsurat hanesi 0 ise ve precision kadar hanesi yoksa 0(lar) ile dolmasını sağlar. Şöyle yaparız. Bu seçeneği noshowpoint ile kapatırız.
coout << fixed << showpoint << setprecision(1);

std::showpos
Sayının başına + veya eksi işareti gelmesini sağlar. Şöyle yaparız.
std::ostringstream oss;
oss << std::showpos; // Always show sign
oss << 1; 

std::cout << oss.str(); // Output: "+1"

std::uppercase
Şöyle kullanırız
cout << hex << uppercase
     <<   "a is " << setfill('0') << setw(2) << int(a)
     << "; b is " << setfill('0') << setw(2) << int(b)
Bu durumda çıktı şöyle olur
a is 00; b is FF

Double
Double için genellikle std::scientific, std::setprecision, std::showpos kullanılır. stream'ler için şöyle bir kod yazabiliriz.
template <class Char>
basic_ostream<Char>& format_double(basic_ostream<Char>& stream) {
    return stream << std::scientific 
                  << std::showpos 
                  << std::setprecision(15);
}
Bu kodu şöyle kullanırız.
cout << format_double << 2.0;
Stringify Metodu
Yukarıdaki format_double metoduna göre daha genel ve güzel bir örnek. Hem variadic template ile istenilen sayıda manipulator belirteçleri kullanılıyor.
template <typename Stream>
Stream& AddManip(Stream& str)
{
    // end the recursion
    return str;
}

template <typename Stream, typename Head, typename... Tails>
Stream& AddManip(Stream& str, Head&& head, Tails&&... tails)
{
    // add the head manipulator and forward the rest
    str << std::forward<Head>(head);
    return AddManip(str, std::forward<Tails>(tails)...);
}

template<typename T, typename... Manip> 
std::string Stringify(T const &value, Manip&&... manip) 
{
    std::stringstream ss;
    // add the manipulators to the stream
    AddManip(ss, std::forward<Manip>(manip)...);
    ss << value;
    return ss.str();
}

int main()
{
  using namespace std;
  cout << Stringify(numeric_limits<int>::max(),setprecision(40),std::hex)<<endl;
}    



1 yorum:

  1. Bu blogu hiçbir zaman bırakmayın lütfen çok seviyorum bu blogu C++'a her ne kadar daha yeni başladıysam bile buraya girip geziyorum çok güzel.

    YanıtlaSil