auto, decltype ve Tür Çıkarımı
C++'ın ilk yıllarında her değişkenin tipini açıkça yazman gerekiyordu. std::vector<std::pair<std::string, int>>::const_iterator it = ... gibi satırlar hem okunması zor, hem de yazılması zahmetliydi. Modern C++ bu sorunu tür çıkarımı (type deduction) ile çözdü.
Bir garson analojisi düşün: "Aynısından bir tane daha" dediğinde garson senin ne içtiğini zaten biliyor — tekrar "soğuk demlenmiş filtre kahve, orta boy, az şekerli" demene gerek yok. auto da aynı şeyi yapar: derleyici sağ taraftaki ifadeye bakarak tipi kendisi çıkarır.
Bu derste auto, decltype ve decltype(auto) mekanizmalarını öğreneceğiz.
auto ile Değişken Tanımlama
auto anahtar kelimesi, derleyiciye "bu değişkenin tipini sen çıkar" der. Değişkenin tipi, başlatma ifadesinden (initializer) otomatik belirlenir.
#include <vector>
#include <map>
#include <string>
#include <iostream>
int main() {
// Temel tipler
auto x = 42; // int
auto y = 3.14; // double
auto z = 'A'; // char
auto name = std::string("Ali"); // std::string
auto flag = true; // bool
// STL container'ları — auto çok faydalı
auto numbers = std::vector<int>{1, 2, 3, 4, 5};
auto ages = std::map<std::string, int>{{"Ali", 25}, {"Ayse", 30}};
// Iterator — auto olmasa çok uzun tip yazardın
auto it = numbers.begin(); // std::vector<int>::iterator
auto cit = ages.cbegin(); // std::map<std::string,int>::const_iterator
std::cout << "x tipi int: " << x << "\n";
std::cout << "Iterator: " << *it << "\n";
return 0;
}auto ile Referans ve const
auto varsayılan olarak değer kopyası oluşturur. Referans veya const istiyorsan açıkça belirtmelisin:
#include <vector>
#include <iostream>
int main() {
std::vector<int> nums = {10, 20, 30};
// Kopya — orijinal etkilenmez
auto val = nums[0];
val = 99;
std::cout << "nums[0]: " << nums[0] << "\n"; // 10 — değişmedi
// Referans — orijinali etkiler
auto& ref = nums[0];
ref = 99;
std::cout << "nums[0]: " << nums[0] << "\n"; // 99 — değişti!
// const referans — okuma için, kopyalama olmadan
const auto& cref = nums[1];
std::cout << "cref: " << cref << "\n"; // 20
// cref = 50; // HATA! const referans
// Pointer
auto ptr = &nums[2];
std::cout << "*ptr: " << *ptr << "\n"; // 30
return 0;
}Range-Based For'da auto
#include <vector>
#include <string>
#include <iostream>
int main() {
std::vector<std::string> names = {"Ali", "Ayse", "Mehmet"};
// Kopya — her iterasyonda string kopyalanır (yavaş!)
for (auto name : names) {
std::cout << name << " ";
}
std::cout << "\n";
// const referans — kopyalama yok, değiştirme yok (en yaygın)
for (const auto& name : names) {
std::cout << name << " ";
}
std::cout << "\n";
// Referans — değiştirmek istersen
for (auto& name : names) {
name = "Degisti";
}
return 0;
}💡 Kural: Range-based for'da
const auto&kullanmayı alışkanlık edin. Değiştirmek istiyorsanauto&, kopyalamak istiyorsan (nadir)auto.
auto ile Fonksiyon Dönüş Tipi
C++14'ten itibaren fonksiyonların dönüş tipi olarak auto kullanabilirsin. Derleyici return ifadesinden tipi çıkarır.
#include <vector>
#include <string>
#include <iostream>
// Dönüş tipi auto — derleyici int çıkarır
auto add(int a, int b) {
return a + b;
}
// Template ile birlikte
template<typename T>
auto square(T x) {
return x * x;
}
// Birden fazla return — tipleri aynı olmalı
auto classify(int score) -> std::string {
if (score >= 90) return "A";
if (score >= 80) return "B";
if (score >= 70) return "C";
return "F";
}
int main() {
std::cout << add(3, 5) << "\n"; // 8
std::cout << square(4) << "\n"; // 16
std::cout << square(3.5) << "\n"; // 12.25
std::cout << classify(85) << "\n"; // B
return 0;
}Trailing Return Type (Sondaki Dönüş Tipi)
C++11'de tanıtılan bu söz dizimi, dönüş tipini fonksiyon parametrelerinden sonra yazar:
#include <iostream>
// Trailing return type — parametreleri görerek tip belirle
template<typename T, typename U>
auto multiply(T a, U b) -> decltype(a * b) {
return a * b;
}
int main() {
auto result1 = multiply(3, 4.5); // double
auto result2 = multiply(2, 3); // int
std::cout << result1 << "\n"; // 13.5
std::cout << result2 << "\n"; // 6
return 0;
}decltype — İfadenin Tipini Alma
decltype bir ifadenin tipini derleyici zamanında belirler. auto başlatma ifadesinden tip çıkarır; decltype ise herhangi bir ifadenin tipini alır — o ifadeyi çalıştırmadan.
#include <vector>
#include <iostream>
int main() {
int x = 42;
double y = 3.14;
// decltype — ifadenin tipini al
decltype(x) a = 10; // int (x'in tipi)
decltype(y) b = 2.71; // double (y'nin tipi)
decltype(x + y) c = 0; // double (int + double = double)
// Container'ın eleman tipi
std::vector<int> nums = {1, 2, 3};
decltype(nums)::value_type val = 42; // int
// Fonksiyon dönüş tipinden yararlanma
decltype(nums.size()) count = 0; // std::vector<int>::size_type
std::cout << "a: " << a << " (int)\n";
std::cout << "c: " << c << " (double)\n";
return 0;
}decltype'ın İnce Noktaları
decltype iki farklı davranış sergiler:
İsim verilirse (parantez olmadan): o ismin tanımlandığı tip döner
İfade verilirse (parantezli dahil): ifadenin değer kategorisini de dikkate alır
#include <iostream>
int main() {
int x = 42;
decltype(x) a = 10; // int — x bir isim
decltype((x)) b = x; // int& — (x) bir lvalue ifade!
b = 99;
std::cout << "x: " << x << "\n"; // 99 — b referans olduğu için!
return 0;
}⚠️ `decltype(x)` ile `decltype((x))` farklıdır! Tek parantez eklemek sonucu tamamen değiştirebilir.
decltype(x)int dönerken,decltype((x))int& döner çünkü(x)bir lvalue ifadedir.
auto vs Explicit Type — Ne Zaman Hangisi?
auto her yerde kullanılmalı mı? Hayır. Bazı durumlarda açık tip yazmak daha iyidir.
auto Kullan
// 1. Iterator tipleri — çok uzun
auto it = myMap.find("key");
// 2. Lambda — tipi zaten yazılamaz
auto lambda = [](int x) { return x * 2; };
// 3. Sağ taraf tipi açık belli
auto name = std::string("Ali");
auto count = static_cast<int>(vec.size());
// 4. Template fonksiyon dönüşleri
auto result = someTemplateFunction<int, double>(args);Explicit Tip Yaz
// 1. Tip belirsizliği olabilecek durumlar
double ratio = 1 / 3; // 0! (int / int)
// auto ratio = 1 / 3; // 0 — niyetini belli etmiyor
double ratio2 = 1.0 / 3; // 0.333... — açık ve net
// 2. API sınırlarında — fonksiyon imzaları
int calculateScore(const Student& s); // Tip bilgisi dokümantasyon
// 3. Tip dönüşümü önemliyse
size_t index = 0; // İşaretsiz olması önemli
int32_t errorCode = 0; // Belirli genişlik önemliGenel Kılavuz
| Durum | Tercih |
|---|---|
| Iterator tipleri | auto ✅ |
| Lambda değişkenleri | auto ✅ |
Basit literal'ler (int x = 5) | İkisi de olur |
| Açık tip dönüşümü gereken yerler | Explicit ✅ |
| Fonksiyon parametreleri | Explicit ✅ (auto sadece generic lambda'da) |
| Range-based for | const auto& ✅ |
decltype(auto)
C++14'te gelen decltype(auto), auto'nun tür çıkarım kuralları yerine decltype'ın kurallarını kullanır. En sık kullanıldığı yer: referans döndüren fonksiyonlarda dönüş tipinin doğru korunması.
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> names = {"Ali", "Ayse", "Mehmet"};
// auto — referansı kaybeder, kopya döner
auto getFirst_auto() {
return names[0]; // string kopyası döner
}
// decltype(auto) — referansı korur
decltype(auto) getFirst_decltype() {
return names[0]; // string& döner (operator[] referans döndüğü için)
}
int main() {
auto copy = getFirst_auto(); // string kopyası
decltype(auto) ref = getFirst_decltype(); // string& referansı
ref = "Degisti";
std::cout << names[0] << "\n"; // Degisti — referans ile değiştirdik
return 0;
}Perfect Forwarding'de decltype(auto)
#include <iostream>
#include <utility>
template<typename F, typename... Args>
decltype(auto) call(F&& f, Args&&... args) {
return std::forward<F>(f)(std::forward<Args>(args)...);
}
int& getRef(int& x) { return x; }
int getValue() { return 42; }
int main() {
int x = 10;
// Referans dönen fonksiyonu çağır — decltype(auto) referansı korur
decltype(auto) ref = call(getRef, x);
ref = 99;
std::cout << x << "\n"; // 99
// Değer dönen fonksiyonu çağır
decltype(auto) val = call(getValue);
std::cout << val << "\n"; // 42
return 0;
}💡 `decltype(auto)` ne zaman kullan? Sadece dönüş tipinin referans mı yoksa değer mi olduğunun korunması gerektiğinde. Günlük kullanımda
autoçoğu zaman yeterlidir.
Structured Bindings ile auto (Ön Bakış)
C++17'de gelen structured bindings, auto ile birden fazla değeri aynı anda açar (decompose). Detayları bir sonraki derste göreceğiz ama burada kısaca gösterelim:
#include <map>
#include <string>
#include <iostream>
int main() {
std::map<std::string, int> ages = {{"Ali", 25}, {"Ayse", 30}};
// Structured binding — auto ile birden fazla değişken
for (const auto& [name, age] : ages) {
std::cout << name << ": " << age << "\n";
}
// Pair açma
auto [minIt, maxIt] = std::minmax({3, 1, 4, 1, 5, 9});
std::cout << "Min: " << minIt << ", Max: " << maxIt << "\n";
return 0;
}Pratik Örnekler
Tip Güvenli Hesaplama
#include <vector>
#include <numeric>
#include <iostream>
int main() {
std::vector<int> scores = {85, 92, 78, 95, 88};
// size_type ile güvenli karşılaştırma
auto total = std::accumulate(scores.begin(), scores.end(), 0.0);
auto count = scores.size(); // size_t (unsigned)
auto average = total / count;
std::cout << "Ortalama: " << average << "\n";
// decltype ile uyumlu tip oluşturma
decltype(average) bonus = 5.0;
std::cout << "Bonuslu: " << average + bonus << "\n";
return 0;
}auto ile Template Basitleştirme
#include <map>
#include <vector>
#include <string>
#include <iostream>
int main() {
// auto olmadan — tür cehenneminden bir kesit
std::map<std::string, std::vector<int>> studentGrades;
studentGrades["Ali"] = {85, 90, 78};
studentGrades["Ayse"] = {95, 88, 92};
// auto ile — çok daha temiz
for (const auto& [name, grades] : studentGrades) {
auto sum = 0.0;
for (const auto& g : grades) {
sum += g;
}
auto avg = sum / grades.size();
std::cout << name << ": " << avg << "\n";
}
return 0;
}Özet
`auto` derleyicinin tipi başlatma ifadesinden çıkarmasını sağlar. Iterator tipleri, lambda değişkenleri ve karmaşık template tipleri için çok faydalıdır.
`auto&` referans, `const auto&` const referans oluşturur. Range-based for'da
const auto&varsayılan tercihin olmalı.`auto` fonksiyon dönüş tipi olarak (C++14+) kullanılabilir. Trailing return type (
-> tip) C++11'de parametrelere bağlı dönüş tipi belirtmek için kullanılır.`decltype` bir ifadenin tipini derleyici zamanında çıkarır — değişken tanımlamada, template'lerde ve tip kontrolünde kullanışlıdır.
decltype(x)vedecltype((x))farklı sonuç verebilir.`decltype(auto)` auto yerine decltype kuralları ile tür çıkarımı yapar — referans döndüren fonksiyonlarda dönüş tipini korumak için kullanılır.
Genel kılavuz: Tip açıksa
autokullan, niyetin belli olması gerekiyorsa veya tip dönüşümü önemliyse explicit tip yaz.
AI Asistan
Sorularını yanıtlamaya hazır