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;

2 yorum:

  1. Merhaba Orçun Bey,

    Bir enum class için neden karşılaştırma operatörlerini yükleyelim? (overload edelim?) Örneğinizdeki RiskLevel türünden değerler zaten karşılaştırılabilir. Yazınızda bir şeyi kaçırmış olabilirim. İyi çalışmalar.

    enum class Suit : unsigned char
    {
    Club,
    Diamond,
    Heart,
    Spade
    };

    #include

    int main()
    {
    Suit s1{ Suit::Heart };
    Suit s2{ Suit::Spade};

    std::cout << std::boolalpha << (s1 < s2);

    }

    Necati Ergin



    YanıtlaSil
  2. Merhaba,
    Normalde < operator'ünü yazmaya gerek yok. Sadece yapılabileceğini gösteren bir örnek bu :)

    YanıtlaSil