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

Hiç yorum yok:

Yorum Gönder