top of page

C++ Dilinde CTAD(Class Template Argument Deduction)

  • Writer: Yusuf Hançar
    Yusuf Hançar
  • Sep 22, 2024
  • 5 min read

C++11 ile birlikte gelen template, programcıların daha genel ve yeniden kullanılabilir kodlar yazmasına olanak tanır. Ancak, şablon kullanımı özellikle türleri belirtmek gerektiğinde karmaşık hale gelebilir. C++17 ile birlikte tanıtılan CTAD, bu durumu büyük ölçüde kolaylaştırarak template argümanlarının otomatik olarak çıkarılmasına olanak tanır.

CTAD, programcıların template kullanırken argüman türlerini açıkça belirtmelerine gerek kalmadan, C++ derleyicisinin bu türleri otomatik olarak çıkarımını sağlar.


Örneğin, bir std::vector oluştururken, türü belirtmek yerine sadece öğeleri sağlayarak bu işlemi gerçekleştirebiliriz:
#include <vector>

int main ()
{
	std::vector ivec = { 1, 2, 3, 4, 5 }; 
}
*****************************     
AÇIKLAMA : C++17 ile CTAD kullanılarak tür otomatik olarak çıkarılır.
*****************************

#include <iostream>
#include <array>

template <typename T>
class Data {
public :
    Data (T x) 
    {
        std::cout << "Data ctor\n";
    }
};

int main () 
{
    Data val(12);                   
}
*****************************     
AÇIKLAMA : CTAD olmasaydı Data<int> val(12); yazmalıydık.
*****************************
CEVAP :  legal
*****************************

int main () 
{
    std::array arr = { 1, 2, 3 };   
}
*****************************     
AÇIKLAMA : çıkarım : array <int, 3U>  olarak yapılır
*****************************
CEVAP :  legal
*****************************

int main ()
{
    std::array<int> arr{ 1, 3, 5 };
}
*****************************     
AÇIKLAMA : çıkarım yapılmaz..
*****************************  

#include <utility>
#include <iostream>

template <typename T>
class Data {
public :
    Data (const T&)
    {
        std::cout << typeid(T).name() << "\n";
    }
};

template <typename T>
Data<T> in_out_func(const T& val) 
{
    return Data<T>(val);
};

int main()
{
    auto ret = in_out_func(5.5);
} 
*****************************     
AÇIKLAMA : Burda auto ile deduction yapıldı olmasaydı eger Data<double> ret seklinde tür acikca belirtilmeliydi.
*****************************     
CEVAP : legal
*****************************

template <typename T>
class Data {
public :
    Data (const T&)
    {        
        std::cout << typeid(T).name() << "\n";
    }
};

int main()
{
    Data val = 10;
}  
*****************************     
AÇIKLAMA : CTAD ile yine çıkarım yapılır.
***************************** 
CEVAP : legal
*****************************
explicit olup olmamasıyla ilgisi yoktur.
template <typename T>
class Data {
public :
    explicit Data (const T&)
    {        
        std::cout << typeid(T).name() << "\n";
    }
};

int main()
{
    Data val = 10;
}  
*****************************     
AÇIKLAMA : çıkarım yapılır ancak hatanın nedeni explicit çağrının bu şekilde yapılamamasıdır.
*****************************     
CEVAP : syntax error
*****************************

template <typename T, std::size_t n>
class Data {
public :
    Data (T(&)[n]){}
};

int main()
{
    int arr[10]{};

    Data my(arr);
}  
*****************************     
AÇIKLAMA : Data<int, 10> my(arr);
*****************************  

template <typename T, typename U, std::size_t n>
class Data {
public :
    Data (T (*)(U(&)[n]))
    {
        std::cout << typeid(T).name() << "\n";
        std::cout << typeid(U).name() << "\n";
    }
};

int foo(double(&)[20])
{
    return 1;
}

int main()
{
    Data fn(foo);
}
*****************************     
AÇIKLAMA : geri dönüş değeri T türü, parametresi n elemanlı diziye referans bir function pointer.
*****************************     
CEVAP : 
i
d
*****************************

template <typename T = double>
struct Data {
    T data;
    Data() : data(){}
    Data(T val) : data{ val }{}
};

int main ()
{
    Data val{ 10 };  // <int>
    Data val1;       // <double>
}

template <typename T = int, typename U = double, typename W = long>
class Data {
public :   
    Data (T t = T{},  U u = U{}, W w = W{})
    {
    }
};

int main ()
{
    Data val(10);
}

int main ()
{
    std::vector vec{ 1, 2, 3 };
    std::list lst{ 1.5, 5.4, 4.6 };
    std::set set1{ 2, 4, 6, 8 };
    std::set set2{ { 2, 5, 8, 10 }, [](int a, int b){ return b < a; } };
}

template <typename T>
class Data {
public :
    Data(T)
    {
        std::cout << "typeid) is : " << typeid(T).name() << "\n";
    }
};

int main ()
{
    Data val([](int x) { return x * x;});
}
*****************************     
CEVAP : derleyici bir closer type türü çıkardı.
*****************************

int main() 
{
    std::function<int(int)> fn = [](int x) { return x * x; };

    Data<decltype(fn)> val(fn); // yukarıda çıkarımı yapılan tür 
}

CTAD için bazı durumlarda parantez kullanım farketmektedir.
int main() 
{
    std::vector<int> v1(1000); 

    // CTAD ile v1'in içeriğini kopyalar
    std::vector<int> v2{ v1 };  // v2, v1'in içeriğini kopyalar (std::vector<int>)
}

int main() 
{
    std::vector<int> v1(1000); 

    // Parantez ile v1'in içeriğini kopyalama
    std::vector<int> v2(v1); // v1'in içeriğini kopyalar (std::vector<int>)
}

int main()
{
    std::array arr{ 1, 3, 5 };                  // geçerli
    std::array arr{ 1, 3.5, 5.8 };              // geçersiz
    std::array<double> arr{ 1.1, 3.4, 5.9 };    // geçersiz
    std::array<> arr{ 1.2, 3.3, 5.8 };          // geçersiz
}

#include <functional>

int foo(int){ return 1; }
double bar(double, double) { return 1.5; }

struct Functor {
    void operator()(int){}
};

int main()
{    
    std::function f1{ foo };                                 // function<int(int)> f1
    std::function f2{ &foo };                                // function<int(int)> f2
    std::function f3{ bar };                            // function<double(double,double)>
    std::function f4{ Functor{} };                           // function<void(int)> f4
    std::function f5{ [](int x, int y){ return x + y; } };   // function<int(int, int)> f5
}

template <typename>
class TypeTeller;

template <typename T>
class Data {
public :
    Data(const T&)          // T türünün çıkarımı char[4] olur.
    {
        TypeTeller<T> x;    // burası için hata verdi.(incomplete type)
    }

private :
    T val;
};

int main ()
{
    Data dval{ "smartcode" };
}
*****************************     
AÇIKLAMA : incomplete type türünden nesne oluşturulamaz.
*****************************     
CEVAP : syntax error
*****************************

template <typename>
class TypeTeller;

template <typename T>
class Data {
public :
    Data(T&)     // T türünün çıkarım const char[4] olur.
    {
        TypeTeller<T> x;   
    }

private :
    T mx;
};

int main ()
{
    Data m{ "smartcode" };
}
*****************************     
AÇIKLAMA : incomplete type türünden nesne oluşturulamaz.
*****************************     
CEVAP : syntax error
*****************************

template <typename>
class TypeTeller;

template <typename T>
void func(T&& t) 
{
    TypeTeller<T> x;    
}

int main ()
{
    func(10);      
}
*****************************     
AÇIKLAMA : derleyici func a çağrı yapıldığında hata verecektir. 
incomplete type türünden nesne oluşturulamaz.
->PR value expression gönderdik Çıkarım int olarak yapıldı.
->fonksiyonun parametre değişkeni && tani t, ancak T türü int
*****************************  

template <typename>
class TypeTeller;

template <typename T>
void func(T&& t) 
{
    TypeTeller<T> x;    
}

int main ()
{
    int val{ 10 };
    func(val);
}
*****************************     
AÇIKLAMA : T türünün çıkarımı int&, fonksiyonun parametresi ise referansa referans olmayacağı için reference collapsing ile int& olur.
***************************** 

template <typename>
class TypeTeller;

template <typename T>
void func(T&& t) 
{
    TypeTeller<T> x;    
}

int main ()
{
    func<int&&>(10);
}
*****************************     
AÇIKLAMA : sağ taraf değerine sağ taraf değeri &&
***************************** 

CTAD Fonksiyon Parametrelerinde Çalışmaması

  • CTAD, yalnızca template argümanlarının türünü çıkarır; template parametrelerinin türünü çıkarmaz.


#include <iostream>
#include <utility>

// compile error, CTAD can't be used here, should be used (std::pair<int, int> pr)...
void pr_pair(std::pair pr) 
{
    std::cout << pr.first << ' ' << pr.second << '\n';
}

int main()
{
    std::pair pr { 1, 2 }; // pr deduced to std::pair<int, int>
    pr_pair(pr);

    return 0;
}

#include <iostream>
#include <utility>

template <typename T, typename U> // deduced T and U types
void pr_pair(std::pair<T, U> pr)
{
    std::cout << pr.first << ' ' << pr.second << '\n';
}

int main()
{
    std::pair pr { 1, 2 }; // pr deduced to std::pair<int, int>
    pr_pair(pr);

    return 0;
}

 
 
 

Recent Posts

See All
C++ Dilinde [[nodiscard]] attribute

C++’ta [[attribute]] (öznitelik) mekanizması, kod hakkında ek bilgi sağlayarak derleyicinin uyarılar vermesine, belirli optimizasyonlar...

 
 
 
C++ Dilinde constinit

C++20'de tanıtılan önemli bir özellik `constinit`'dir; bu özellik, statik depolama süresine sahip değişkenlerin derleme zamanında...

 
 
 

Comments


bottom of page