Enum etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Enum etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

1 Temmuz 2019 Pazartesi

Strongly Typed Enum

Giriş
C++11 ile gelen yeni bir özellik. enum kelimesinden sonra class kelimesi eklenerek Strongly Typed Enum oluşturulur. Şöyle yaparız.
enum class PlayerPiece {
  AIRCRAFT,
  BATTLESHIP,
  CRUISER,
  SUBMARINE,
  PATROL,
  EMPTY,
 };
C++11 ile gelen diğer değişiklikler gibi saklama tipi (storage type) ve sıra numarası (ordinal number) verebiliriz. Şöyle yaparız.
enum class CustomCommand : unsigned char
{
    ENQ = 0x05,
    ACK = 0x06,
    NAK = 0x15,
};
Strongly Typed Enum Class mı?
class kelimesini kullanmamıza rağmen Strongly Typed Enum class değil. Cevabı görmek için şöyle yaparız. Çıktı olarak false alırız.
#include <iostream>

enum class Enum 
{
  red = 1, blue, green
};

int main() 
{
  std::cout << std::boolalpha;
  std::cout << std::is_class<Enum>::value << '\n';
}
Primitive Tipe Çevirmek - static_cast
Açıklaması şöyle
There are no implicit conversions from the values of a scoped enumerator to integral types, although static_cast may be used to obtain the numeric value of the enumerator.
Şöyle yaparız.
PlayerPiece piece = ...

cout << static_cast<int>(piece) << endl;
Eğer static_cast kullanmazsak şu hatayı alırız.
error: cannot convert 'PlayerPiece' to 'unsigned char'...
Primitive Tipe Çevirmek - std::underlying_type
Bazı kodlarda underlying type için const qualifier kullanılıyor. Bu qualifier aslında dikkate alınmaz. Açıklaması şöyle.
colon (:), followed by a type-specifier-seq that names an integral type (if it is cv-qualified, qualifications are ignored) that will serve as the fixed underlying type for this enumeration type
Yani şu koddaki const'un bir özelliği yok.
enum foo : const unsigned int
{
    F,
    S,
    T
};
Örnek
Şöyle yaparız.
enum class foo_bar : unsigned
{
  foo,
  bar,
};

foo_bar bar = foo_bar::bar;
unsigned a = static_cast<std::underlying_type<foo_bar>::type>(bar);
Örnek
Şöyle yaparız.
typedef std::underlying_type<foo_bar>::type int_type;
stringstream ss;
ss << int_type(rl);
Operator Metodları Tanımlamak

operator <<  metodu
Şöyle yaparız.
std::ostream& operator<<(ostream& os, RiskLevel rl) {
  os << std::underlying_type<RiskLevel>::type(rl);
  return os;
}
operator <  metodu
Şöyle yaparız.
bool operator<(RiskLevel rl1, RiskLevel rl2) {
  return std::underlying_type<RiskLevel>::type(rl1) <
         std::underlying_type<RiskLevel>::type(rl2);
}
operator + metodu
int tipe çevirmek için kullanılır. Şöyle yaparız.
auto operator + ( RiskLevel value )
{
  return std::underlying_type_t< RiskLevel >( value );
}
Şöyle yaparız.
stringstream ss;
ss << + rl;
Şöyle yaparız.
if ( + rl > + RiskLevel::Low ) {
  ... 
}
operator ++ (int) metodu - post increment
İmzası şöyle
STEPS operator++(STEPS& s, int)
{
  auto res = s; ++s; return res;
}
operator ++ metodu - pre increment
Şöyle yaparız
enum class STEPS
{
  ONE,
  TWO,
  END_OF_LIST
};

STEPS& operator++(STEPS& s)
{
  ...
  return s;
}
Kullanmak için şöyle yaparız
++steps;

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