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.
CSD C ve Sistem Programcıları Derneği