C++ Dilinde CTAD(Class Template Argument Deduction)
- 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;
}
Comments