Variant Sınıfı
Giriş
Şu satırı dahil ederiz.
Parametre Sayısı
Sayı 20 ile sınırlı. Eğer değiştirmek istersek BOOST_MPL_LIMIT_LIST_SIZE ile değiştirilebilir. Bu sayının 10'un katı olması gerekir. Yani 30,40,50 olabilir. Üst sınıf 50'dir. Şöyle yaparız.
Kötü Örnekler
Örnek
Variant static polymorphisim için kullanılır. Dolayısıyla birbirlerinden kalıtan tipler için kullanmak mantıklı değil. Kötü bir variant örneği için şöyle yaparız.
variant sınıfı içerdiği tiplerin alanlarına direkt erişim sağlamaz. Açıklaması şöyle
Tanımlanan tipin CopyConstructible ve MoveConstructible olması gerekir. Açıklaması şöyle
Bu metod aslında variant sınıfına ait değil ancak buraya yazmayı daha uygun buldum. Variant içindeki değere referans ile erişmek için boost::get(...) kullanılabilir. Eğer boost::get(...) istenilen tipe dönüştüremiyorsa exception fırlatır.
Örnek
Elimizde şöyle bir variant olsun.
Giriş
Şu satırı dahil ederiz.
#include <boost/variant.hpp>
Açıklaması şöyleYou can think about boost::variant as a improved C++ union.Union'daki her tanım farklı bir tip olduğu için hep aynı tipi içeren şöyle bir variant mantıklı değil.
boost::variant<T, T>
İleride std::variant sınıfı da standarda girebilir. boost::variant hem farklı tipleri aynı değişkende saklamak, hem de "template covariance" için kullanılır.Parametre Sayısı
Sayı 20 ile sınırlı. Eğer değiştirmek istersek BOOST_MPL_LIMIT_LIST_SIZE ile değiştirilebilir. Bu sayının 10'un katı olması gerekir. Yani 30,40,50 olabilir. Üst sınıf 50'dir. Şöyle yaparız.
#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
#define BOOST_MPL_LIMIT_LIST_SIZE 30
Kötü Örnekler
Örnek
Variant static polymorphisim için kullanılır. Dolayısıyla birbirlerinden kalıtan tipler için kullanmak mantıklı değil. Kötü bir variant örneği için şöyle yaparız.
using Shape = boost::variant<Rectangle, Circle>;
Örnekvariant sınıfı içerdiği tiplerin alanlarına direkt erişim sağlamaz. Açıklaması şöyle
The variant type doesn't have the .hello and .bye members. You can access them via a "visitor" function.Şu kod derlenmez.
class A {
public:
struct greeting {
string hello;
};
};
class B {
public:
struct greeting {
string bye;
};
};
typedef boost::variant<A::greeting, B::greeting> greet;
greet getG(string key) {
greet g;
if (key == "A") {
g.hello = "MY ENEMY"; // this line doesn't work
}
else {
g.bye = "MY FRIEND"; // nor this line
}
return g;
};
ConstructorTanımlanan tipin CopyConstructible ve MoveConstructible olması gerekir. Açıklaması şöyle
Şöyle yaparız.Every bounded type must fulfill the requirements of the MoveAssignable concept.
struct empty_type {};
using cell_type = boost::variant<std::string, double, empty_type>;
Ya da şöyle yaparız.typedef boost::variant<std::string,int> StringOrInt;
Daha sonra variant nesnesine bir değer atarız. Şöyle yaparız.StringOrInt v = 0;
veya şöyle yaparız.StringOrInt v= "42";
Eğer tip move assignment metoduna sahip değilse hata alırız. Move constructor tanımlanınca, move assignment derleyici tarafından üretilmediği için derlenmez.#include <boost/variant.hpp>
struct Foo {
Foo(Foo&&) { }
};
int main() {
boost::variant<int, Foo> v;
v = 42;
}
get metoduBu metod aslında variant sınıfına ait değil ancak buraya yazmayı daha uygun buldum. Variant içindeki değere referans ile erişmek için boost::get(...) kullanılabilir. Eğer boost::get(...) istenilen tipe dönüştüremiyorsa exception fırlatır.
std::variant ile boost::variant'ın ayrıldıkları bir nokta var. std::get ile indeks kullanarak istenilen tipe dönüşüm sağlanabilir. Şöyle yaparız.
std::get<0>(v);
boost::get() bu yeteneği sağlamıyor ancak bir miktar kod ile kolayca çözülebilir.Örnek
Elimizde şöyle bir variant olsun.
boost::variant<User*, Stuff*> v;
Şöyle yaparız.User **user = boost::get<User*>(&v);
type metodu
Bu metodu kullanarak if koşulları kodlamak yerine boost::static_visitor kullanmak daha iyi olabilir.
Örnek
Şöyle yaparız.
Örnek
Şöyle yaparız.
if(myVariantInstance.type() == typeid(ConcreteType))
{...}
Örnek
Elimizde iki tip içeren bir variant olsun Şöyle yaparız.
Elimizde iki tip içeren bir variant olsun Şöyle yaparız.
boost::variant<Rectangle, Triangle> v = ...;
if (v.type() == typeid(Rectangle)) {
...
} else if (v.type() == typeid(Triangle)){
...
}
which metodu
Variant içindeki değere referans ile erişmek için boost::get + variant.which() kullanılabilir. Açıklaması şöyle
Such a getter already exists: boost::get<> function template.Elimizde şöyle bir variant olsun
However, keep in mind that the variant contents is set at run-time, so it is absolutely impossible to know it at compile-time.
That's why you should tell get function template what type you want it to return - and if the variant does not contain it at that point of time, it will throw exception.
Alternatively, you could use variant::which() member function, which returns an index of the current type - which is also a run-time value.
using VariantType = boost::variant<
std::shared_ptr<StructA>,
std::shared_ptr<StructB>
>;
Variant'i şöyle ilkendireyim
VariantType variant = std::make_shared<StructA>(1, 'a', 3);
which metodunu çağırayım.
std::cout << variant.which() << std::endl;
İlk tipi kullandığım için çıktı olarak 0 alırım.
0
Variant'i bu sefer şöyle ilkendireyim
VariantType variant =
std::make_shared<StructB>('b', 'c');
which metodunu çağırayım.
std::cout << variant.which() << std::endl;
İkinci tipi kullandığım için çıktı olarak 1 alırım.
1
Diğer
Variant'ı Parametre Olarak Geçme
Şöyle yaparız.
Şöyle yaparız.
Şöyle yaparız.
Örnek 1
Tanımlamak için şöyle yaparız.
Şöyle yaparız.
template <typename O, typename E, template <typename...> class VariantType>
VariantType<O, E> foo (O o)
{
return VariantType<O, E>{std::move(o)};
}
boost::variant<int, std::string> res = foo <int, std::string, boost::variant>(17);
Variant Listesi Şöyle yaparız.
using V = boost::variant< int, std::string>;
for (V v : { V{5}, V{"something"} })
boost::apply_visitor(myvisitor(), v);
Variant Vector'üŞöyle yaparız.
vector<StringOrInt> values;
values.push_back (0);
values.push_back (
"42");
Yazdırmak için şöyle yaparız.for (int i = values.size()-1; i > 0; --i)
std::cout << values[i] ;
Variant Map'iÖrnek 1
Tanımlamak için şöyle yaparız.
std::map<std::string,boost::variant< int*, std::string*>> options;
Şöyle yaparız.std::string key = ...;
int value = ...;
*boost::get<int
*>(options.find(name)->second) = value;
Örnek 2
Şöyle yaparız.
recursive_wrapper yazısına taşıdımŞöyle yaparız.
using Key = boost::variant<int, std::string>;
using Map = std::map<Key, std::string>;
Map m;
m[1] = "aaa";
m["myKey"] = "bbb";
recursive_wrapper
Hiç yorum yok:
Yorum Gönder