31 Ocak 2017 Salı

OutputIterator

Giriş
5 tane iterator kategorisi var. Bunlar
1. input_iterator_tag - InputIterator yazısına bakınız.
2. output_iterator_tag - Bu yazı.
3. forward_iterator_tag - ForwardIterator yazısına bakınız.
4. bidirectional_iterator_tag,
5. random_access_iterator_tag - RandomAccessIterator yazısına bakınız

forward_iterator_tag,bidirectional_iterator_tag ve random_access_iterator_tag yapıları aynı zamanda output_iterator_tag'den kalıtır.

Açıklaması şöyle
Assignment through the same value of an output iterator happens only once: algorithms on output iterators must be single-pass algorithms.

STL içindeki InputIterator ve OutputIterator kullanan algoritmalar şunlar.

Nasıl Tanımlanır
Sınıf şöyle tanımlanır
class infix_ostream_iterator :
    public std::iterator<std::output_iterator_tag,void,void,void,void>
{...}
operator copy assignment  metodu
Bu metod tanımlı değilse VS 2012'den itibaren hata alırız.

operator = metodu
Output Iterator sınıfının en önemli metodu = operatörüdür. Burada yapılması gereken iş yapılır.
infix_ostream_iterator<T,charT,traits>& operator=(T const &item)
{
   ...
   return *this;
}
operator * metodu
Şöyle yaparız. Bu metodu genelde doldurmaya gerek olmaz.
infix_ostream_iterator<T,charT,traits> &operator*() {
        return *this;
}
operator ++ metodu
Şöyle yaparız. Bu metodu doldurmak gerekir.
infix_ostream_iterator<T,charT,traits> &operator++() {
        return *this;
}
operator ++ metodu
Şöyle yaparız. Bu metodu genelde doldurmaya gerek olmaz.
infix_ostream_iterator<T,charT,traits> &operator++() {
  return *this;
}
Yazma İşlemi
"Output iterators can only step forward with write access. Writing data without checking for end of sequence is correct. In fact, you can't operate an output iterator with an end iterator because output iterators do not have to provide a comparison operation."
Aşağıdaki kod parçası end() kullanmadığı için doğrudur.

while (true) {
 *pos = foo ();
 ++pos;
}

Bu kod parçası ise end() kullandığı için output iterator açısından imkansızdır.

while (pos != end()) {
 *pos = foo ();
 ++pos;
}




28 Ocak 2017 Cumartesi

Enumeration

Giriş
Bu yazıda normal enum anlatılıyor. C++11 ile ile Strongly Typed Enum'u farklı bir yazıda ele aldım.

Enum'u Dolaşmak
Basit bir enum şöyle dolaşılır.
enum color {
  YELLOW,
  GREEN,
  BLUE,
  RED,
  /* Please, add new color BEFORE this comment */
  NB_COLOR
};

for (int i = 0; i < NB_COLOR; ++i) {
   /* Do something */
}
Eğer enum'lara elle değer verilmişse ve sayıları çoksa şöyle bir şey yapılabilir. Ama ben bu yöntemi tercih etmem.
enum color
{
  ENUM_START = __LINE__,
  YELLOW = 123,
  GREEN = 456,
  ENUM_ITEMS = __LINE__ - ENUM_START - 1
};
Enum İçin Kullanılan Integral Tip
C++ standardı enum için kullanılması gereken integral type'ı belirtmez. C++'ta çoğu derleyici int tipini kullanır. C'de ise açıklama şöyle
Constraints: The expression that defines the value of an enumeration constant shall be an integer constant expression that has a value representable as an int.
Dolayısıyla C ve C++ burada ayrılıyorlar. Ayrımı görmek için şöyle yaparız.
#include <stdio.h>
#include <limits.h>
#include <inttypes.h>

int main() {
  enum en_e {
    en_e_foo,
    en_e_bar = UINT64_MAX,
  };
  enum en_e e = en_e_foo;
  printf("%zu\n", sizeof en_e_foo);
  printf("%zu\n", sizeof en_e_bar);
  printf("%zu\n", sizeof e);
}
Çıktı olarak C'de şunu alırız.
4,4,8
Çıktı olarak C++'ta şunu alırız.
8,8,8
Aslında şu kod C için hatalıdır ve derleyici hata mesajı üretmelidir.
enum en_e{
    en_e_foo,
    en_e_bar=UINT64_MAX,
};
Açıklaması şöyle. Çünkü int'in alabileceği en büyük değerden fazlası atanmaya çalışılıyor.
A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, [...]
Enum'dan Kalıtmak
C++11 ile enum belirtilen tipten kalıtabilir. Şöyle yaparız
enum A : char { a = 1, b, c }; 
       ^^^^^^
Enum ve Atanan Değer
Şöyle yaparız
enum RxqType
{
  A = (1 << 0),
  B = (1 << 1),
  C = (A | B),
  D = A+B+C
};

Değerden Enum'a Çevirme
Bir sayı static_cast ile enum'a çevrilebilir. Ancak sayı enum'un aralığı dışındaysa davranış tanımsızdır. Açıklaması şöyle
A value of integral or enumeration type can be explicitly converted to a complete enumeration type. The value is unchanged if the original value is within the range of the enumeration values (7.2). Otherwise, the behavior is undefined.
Örnekte enum 0,1 değerleri arasında. 3'ün enum'a çevrilmesi yanlış.
enum class E : bool { A, B };

void foo(E e)
{
  switch(e)
  {
    case E::A: break;
    case E::B: break;
    default: std::cout << "aha\n";
  }
}

int main()
{
  foo( static_cast<E>(3) );
}
String'den Enum'a Çevirmek
Şöyle yaparız.
enum Choice {Unknown, One, Two, Three};

Choice getChoice(std::string const& s)
{
  static std::map<std::string, Choice> theMap =
    {{"One", One}, {"Two", Two}, {"Three", Three}};
  return theMap[s];
}

std::any

Giriş
Açıklaması şöyle. Veriyi void* olarak saklar.
std::any has to be implemented with type-erasure. That's because it can store any type and can't be a template. There is just no other functionality in C++ to achieve this at the moment.

What that means is that std::any will store a type-erased pointer, void* and std::any_cast will convert that pointer to the specified type and that's it.
Small Object Optimization
Bu sınıf small object optimization yöntemini belki uygulayabilir ancak garanti sağlamaz. Açıklaması şöyle.
Implementations should avoid the use of dynamically allocated memory for a small contained object. [ Example: where the object constructed is holding only an int.  — end example ] Such small-object optimization shall only be applied to types T for which is_­nothrow_­move_­constructible_­v<T> is true.
std::any_cast metodu
Bu sınıftaki nesneye erişmek için std::any_cast kullanılır.

26 Ocak 2017 Perşembe

std::result_of

Giriş
Belirtilen metodun sonuç tipine erişmemizi sağlar.

Nesne Fully Defined Olmalıdır
Metod bir nesne içinde ise nesnenin tanımlanmasının bitmiş olması gerekir. Şu kod derlenmez.
struct Foo
{
  static auto foo(int bar)
  {
    return 0;
  }

  typedef std::result_of<decltype(Foo::foo)> foo_t;
};
Çıktı olarak şunu alırız.
"function 'foo' with deduced return type cannot be used before it is defined"
Sebebi ise kodun aslında şuna benzemesi. Foo header'ı parse edilirken önce declaration bulunur. Dolayısıyla foo metonun ne döndüğünü derleyici bilemez.
struct Foo
{
  static auto foo(int bar);

  typedef std::result_of<decltype(Foo::foo)> foo_t;
};

auto Foo::foo(int bar)
{
  return 0;
}

Örnek 1
Şöyle yaparız.
#include<type_traits>
#include<iostream>
using namespace std;


template <class F, class R = typename result_of<F()>::type>
R call(F& f) { return f(); }

struct S {
    double operator()(){return 0.0;}
};

int main()
{
  S obj;
  call(obj);//ok

  return 0;
}
Örnek 2
auto metodlar ile de kullanılabilir. Şöyle yaparız
auto foo(int bar)
{
  return 0;
}

typedef std::result_of<decltype(foo)> foo_t;
Şöyle yaparız.
struct Foo
{
  static auto foo(int bar)
  {
    return 0;
  }
};

typedef std::result_of<decltype(Foo::foo)> foo_t;



Lock Sınıfları

Otomatik Kilitleme Sınıfları
STL içindeki otomatik kilitleme için kullanılabilen iki sınıftan var. Bunlar std::lock_guard ve std::unique_lock.

1. lock_guard Sınıfı
std::lock_guard Sınıfı yazısına taşıdım.

2. unique_lock sınıfı
constructor tag'leri
Bu sınıf 3 tip constructor destekliyor.
unique_lock( mutex_type& m, std::defer_lock_t t );
unique_lock( mutex_type& m, std::try_to_lock_t t );
unique_lock( mutex_type& m, std::adopt_lock_t t );
Her tip aslında bir tag. Bu yönteme tag dispatching deniliyor. Tag için struct'lar şöyle tanımlanmış.
struct defer_lock_t { };
struct try_to_lock_t { };
struct adopt_lock_t { };
Tag'ler ise şöyle tanımlı
constexpr std::defer_lock_t defer_lock {};
constexpr std::try_to_lock_t try_to_lock {};
constexpr std::adopt_lock_t adopt_lock {};
boost ile benzerliği
Bu sınıf boost içindeli scoped_lock ile aynı. scoped_lock şöyle kullanılırdı.
boost::mutex::scoped_lock lock(_mutex, boost::try_to_lock);
if( lock ) {

}
constructor
Şöyle yaparız.
std::mutex m;
auto my_lock = std::unique_lock<std::mutex> (m);
Ya da şöyle  yaparız.
using mutex_type = std::mutex;
using lock_type = std::unique_lock<mutex_type>;

mutex_type m;

auto lock = lock_type(m);
operator boolean - Kilidi Kontrol Etme
Şöyle de yapabiliriz.
std::mutex mutex;
std::unique_lock<std::mutex> lock(mutex, std::try_to_lock);
if (lock) {
  ...
}
owns_lock metodu - Kilidi Kontrol Etme
Şimdiye kadar hiç bu metodu kullanmam gerekmedi. Kullanım yeri olarak aklıma şöyle bir örnek geliyor. Eğer bir thread periyodik çalışıyorsa ve bir başka thread tarafından engellenmek istemiyorsa mutex'i almayı dener. Başarırsa devam eder, başaramazsa bloke olmadan bir sonraki sefere denemek üzere başka bir iş yapar.
std::unique_lock<std::mutex> lock(initMutex, std::try_to_lock);
if(!lock.owns_lock())
{
  ...
}
unlock metodu
Destructor'dan önce kilidi bırakmak istersek şöyle yaparız.
lock.unlock();
3. std::lock metodu
std::lock metodu yazısına taşıdım

4. std::try_lock metodu
std::try_lock metodu yazısına taşıdım