Elinde sadece çekiç olan birine bütün sorunlar çivi gibi görünür.

Anonim

C++0x – auto, decltype Tür Belirleyicileri

    auto anahtar sözcüğü C ve C++’da yer belirleyicisi (storage class specifier) olarak kullanılmaktadır. C++’ın son aşamaya gelmiş yeni standartlarında ise auto anahtar sözcüğü yer belirleyicisi olmaktan çıkartılmış ve tür belirleyicisi yapılmıştır.  

decl-specifier:
    storage-class-specifier
    type-specifier
    function-specifier
    friend
    typedef
    constexpr
    alignment-specifier

type-specifier:
    simple-type-specifier
    class-specifier
    enum-specifier
    elaborated-type-specifier
    typename-specifier
    cv-qualifier

simple-type-specifier:
    ::opt nested-name-specifieropt
type-name
    ::opt nested-name-specifier template
simple-template-id
    char
    char16_t
    char32_t
    wchar_t
    bool
    short
    int
    long
    signed
    unsigned
    float
    double
    void
    auto
    decltype ( expression )

auto belirleyicisi ile ilkdeğer verilen bir nesnenin türü derleyici tarafından verilen ilkdeğerin türüne bakılarak belirlenir. Örneğin:

auto a = 10;                 // a int türden
const auto p = &a;           // p const int * türünden


Tür belirleme süreci şablon işlemlerindeki gibi yürütülmektedir. (Eğer bu sürecin ayrıntılarıyla ilgileniyorsanız standartlarda belirtilen Template Argument Deduction işlemlerini incelemelisiniz.)

auto belirleyicisi özellikle şablonlarla (templates) birlikte kullanıldığında yazımı oldukça kolaylaştırmaktadır:  

std::vector<int> v;
//...
for (auto iter = v.begin(); iter != v.end(); ++iter) {
    //...
}

Burada iter değişkeni std::vector<int>::iterator türündendir.  

auto belirleyicisi ile bildirilen değişkenlere ilkdeğer verilmek zorundadır. N1984 döümanındaki aşağıdaki örnekleri inceleyiniz:

int foo();
auto x1 = foo();             // x1 ---> int türünden
const auto &x2 = foo();      // x2 ---> const int & türünden
auto &x3 = foo();            // geçersiz, x3 ---> int & türünden.

float &bar();
auto y1 = bar();             // y1 ---> float türünden
const auto& y2 = bar();      // y2 ---> const float & türünden
auto &y3 = bar();            // y3 ---> float & türünden

A *fii();
auto *z1 = fii();            // z1 ---> A * türünden  
auto z2 = fii();             // z2 ---> A* türünden
auto *z3 = bar();            // geçersiz! göstericiye float atanmak istenmiş

...
A foo();
A& bar();
A x1 = foo();                // x1 ---> A türünden  
auto x1 = foo();             // x1 ---> A türünden

A &x2 = foo();               // geçersiz, referans const olmalı  
auto& x2 = foo();            // geçersiz, referans const olmalı  
A y1 = bar();                // y1 ---> A türünden

auto y1 = bar();             // y1 ---> A türünden

A& y2 = bar();               // y2 ---> A & türünden

auto& y2 = bar();            // y2 ---> A & türünden


Şüphesiz auto belirleyicisi ile birden fazla değişken bildirimi yapılabilir:

double a;
auto b = a, *c = &a;         // b ---> double, c ---> double * türünden


Bu durumda -tıpkı şablonlarda olduğu gibi- türlerin tutarlı olması gerekir. Yani auto belirleyicisi yerine bir türün bulunduğunu varsaymalısınız. Başka bir deyişle, her değişken için bağımsız tür belirlemesi yaptığınızda bu türlerin aynı olması gerekir. Örneğin:

auto a = 10,  b = 20L;       // geçersiz, auto int mi, long mu?

auto tür belirleyicisi new operatörüyle birlikte kullanılabilir. Örneğin:

new auto(20L);               // long türden tahsisat yapılır
auto x = new auto(’a’);      // x ---> char * türünden


decltype belirleyicisi ise bir ifadenin türüne uygun bildirim yapmak amacıyla kullanılmaktadır: Örneğin:

int a;
decltype(a) b;

Burada decltype(a) tür belirleyicisi a’nın türünü temsil eder. a int türden olduğuna göre b de int türdendir. Örneğin:

std::vector<int> v;
//...
for (decltype(v.begin()) iter = v.begin(); iter != v.end(); ++iter) {
    //...
}

Burada v.begin() ifadesi vector::iterator türünden olduğuna göre iter de bu türdendir. decltype belirleyicisinde operand olan ifade hesaplanmaz (sizeof’’da olduğu gibi).

decltype belirleyicisi ile türün nasıl belirlendiğinin bazı ayrıntıları var. Standart taslaklarında şunlar söylenmiş:

e bir ifade belirtmek üzere decltype(e) tür belirleyicisi:

1) Eğer e bir değişken ismi ya da fonksiyon ismi ise (id-expression) ya da bir sınıfın elemanına erişme ifadesi ise (class member access) e ifadesinin türünü,

2) Yukardaki durum söz konusu değilse ve e bir fonksiyon çağırma ifadesi ise fonksiyonun geri dönüş değerinin türünü,

3) Yukardaki durum söz konusu değilse ve e bir sol taraf değeri belirtiyorsa ve e’nin türü T ise T & türünü,

4) Yukarıdaki durum söz konusu değilse e ifadesinin türünü belirtir.  

Örneğin:

const int *foo();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1;           // x1 ---> const int * türünden
decltype(i) x2;               // x2 ---> int türünden
decltype(a->x) x3;            // x3 ---> double tründen
decltype((a->x)) x4;          // x4 ---> const double& türünden


Son örnekte (a->x) ifadesi artık sınıf elemanına erişme ifadesi olarak değil sol taraf değeri olarak ele alınmaktadır.



Kaynaklar


1. Jarvi, J., Reis, G., Stroustrup, B., & Reis, G. (2006). Deducing the type of variable from its initializer expression (N1984=06-0054). http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/ adresinden alınmıştır.

2. Jarvi, J., Reis, G., Stroustrup, B., & Reis, G. (2006). Decltype (revision 6)  proposed wording (N2343=07-0203, N2115=06-0185). http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/ adresinden alınmıştır.

3. Jarvi, J., Reis, G., Stroustrup, B., & Reis, G. (2006). Decltype (revision 7)  proposed wording (N2343=07-0203). http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/ adresinden alınmıştır.

4. Working Draft, Standard for Programming Language C++ (N2798=08-0308). (2008). http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/adresinden alınmıştır.

Haftanın Böceği Yukarı