C++11 – std::tuple üzerine

STL’ i kullananlar bilirler genelde iki farklı türden anlamsal birliktelikleri olan değişkenleri tutmak için genelde std::pair kullanılırdı.

pair<int, string> pt (1, "herbibk");
cout << pt.first << "-" << pt.second << endl;

C++11 ile gelen veri yapılarından biri olan std::tuple’ la birlikte bu özellik sınırsız türde nesneyi sınırsız sayıda içermeye kadar gitti. Üstelik derleme zamanında veri yapısındaki nesne sayısını da biliyorsunuz.

Aslında tuple’ ın nasıl implemente edildiğine baktığınızda basitçe C++’ ın iki temel özelliğini kullanılmış; Çoklu Türetme (Multiple Inheritance) ve Değişken parametreli şablonlar (variadic templates).

template <typename T>
struct tuple_leaf
{
T value_;
};

template <typename... Types>
class tuple : tuple_leaf<Types>...
{
};

‘tuple_leaf…’ parametre pack’i (türkçesini daha düşünmedim) ifadesi tuple_leaf, tuple_leaf, tuple_leaf….tuple_leaf şeklinde açılacak böylelikle tuple sınıfı da bunlardan çoklu türetmeyle türetilecek.

Fakat burda şöyle bir sıkıntı var, aynı türde nesneler geldiğinde örneğin T1 ve T3 string olduğunda bu yapı çalışmayacak zaten var olan bir sınıf için ikinci defa bir sınıf yazılmayacak ve derleme hatası verilecektir. STL de bu sıkıntıyı aşmak için std::integer_sequence kullnılmış derleme zamanında indis üretmek için. Böylelikle aynı tür nesneler geldiğin de bile indisleri farklı olduğundan farklı bir sınıftan türetiliyormuş gibi olacak. Biraz zorlama bir trick olmuş .)

Peki daha önceki variadic template fonksiyonlarından bahsettiğimiz yazılarımdaki1 gibi recursive bir tanım yaparsak bu sorunları aşabilir miyiz ?

template <class... Ts> struct tuple {};

template <class T, class... Ts>
struct tuple<T, Ts...> : tuple<Ts...> {
tuple(T t, Ts... ts) : tuple<Ts...>(ts...), tail(t) {}

T tail;
};

Yukarılda görüldüğü gibi rekürsiv olarak her bir tür için bir sınıf diğer kalan türlerden türetilerek oluşturulacak.

Aslında şöyle bir yapı ortaya çıkacak;

struct tuple<T1, T2, T3> : tuple<T2, T3> {
T1 tail;
}

struct tuple<T2, T3> : tuple<T3> {
T2 tail;
}

struct tuple<T3&>: tuple {
T3 tail;
}

struct tuple {
}

Rekürsiv olarak tanımlamak biraz kafa karıştırsa da en kısa yol. Standart kütüphaneye bakıldığında bu işi non-recursive yoldan halletmişler. Tuple implementasyonunu meta programming bakış açınızı güçlendirmek adına inceleyebilirsiniz.

Göz at:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
http://blogs.microsoft.co.il/sasha/2015/01/12/implementing-tuple-part-1/