广州建设营销型网站,补习吧 一家专门做家教的网站,希爱力吃一颗能干多久,经典重庆网首页std::variant
可以理解为一个会自动清除空间的union#xff0c;保证了赋值时内存的正确性#xff0c;能够自动进行析构。
通过get可传入下标或者type来获取值#xff0c;但是不安全#xff0c;如果传入类型于当前类型不一致时会引发错误。
可以通过get_if传入下标或者值…std::variant
可以理解为一个会自动清除空间的union保证了赋值时内存的正确性能够自动进行析构。
通过get可传入下标或者type来获取值但是不安全如果传入类型于当前类型不一致时会引发错误。
可以通过get_if传入下标或者值和variant指针来安全获得值。
有类模板variant_alternative来获取第几个属性的type以及类模板variant_size来获取variant中存放了多少个属性。
variantget type get N variant_alternativevariant_sizeoperator
int main() {std::variantint, float a;a 1;auto int_value std::getint(a);std::cout int_value \n;try {auto float_value std::getfloat(a);} catch (const std::bad_variant_access e) {std::cout e.what() \n;}std::cout std::holds_alternativeint(a) std::holds_alternativefloat(a) \n;a 1.1f;std::cout std::holds_alternativeint(a) std::holds_alternativefloat(a) \n;std::cout std::getfloat(a) std::get1(a) \n;// std::cout std::getint(a) std::get0(a) \n;std::cout std::get_if0(a) std::get_ifint(a) \n;std::cout std::get_if1(a) std::get_iffloat(a) \n;std::variant_alternative1, decltype(a)::type f 1.2;std::cout f \n;std::cout std::variant_size_vdecltype(a) \n;return 0;
}sample::variant
存储结构
union模板一层一层嵌套即可得到我们的variant存储结构整体的内存占用情况为sizeof(largestTypeTs...)
templatetypename ...Ts union __union;templatetypename T, typename ...Ts
union __unionT, Ts... {using type __union;using rest_type __unionTs...;using value_type T;T value_;rest_type rest_;templatetypename Tvrequires std::is_same_vstd::decay_tTv, T__union(Tv value) : value_(std::forwardTv(value)) {}template typename Tv__union(Tv rest) : rest_(std::forwardTv(rest)) {}__union() {}~ __union() {}
};templatetypename T
union __unionT {using type __union;using value_type T;T value_;templatetypename Tvrequires std::is_same_vstd::decay_tTv, T__union(Tv value) : value_(std::forwardTv(value)) {}__union() {}~ __union() {}
};简单测试访问一下看看
int a 114;
auto u1 __unionshort int, int, unsigned int, long long, float, double(a);
std::cout u1.value_ u1.rest_.value_ u1.rest_.rest_.value_ u1.rest_.rest_.rest_.value_ u1.rest_.rest_.rest_.rest_.value_ u1.rest_.rest_.rest_.rest_.rest_.value_ \n;const double b 115.514;
auto u2 __unionshort int, int, unsigned int, long long, float, double(b);
std::cout u2.value_ u2.rest_.value_ u2.rest_.rest_.value_ u2.rest_.rest_.rest_.value_ u2.rest_.rest_.rest_.rest_.value_ u2.rest_.rest_.rest_.rest_.rest_.value_ \n;std::string str lifehappy;
auto u3 __unionint, double, std::string(std::move(str));
std::cout u3.value_ u3.rest_.value_ u3.rest_.rest_.value_ : __union\n;
std::cout str : str\n;114 114 114 4294967410 1.59748e-43 2.122e-314 -30409 1614907703 1614907703 4637828992051808567 5.5783e19 115.514 1701210476 4.06896e233 lifehappy : __union : str variant
templatetypename ...Ts
struct variant {using type variant;using data_type __unionTs...;__unionTs... data_;templatetypename Tvvariant(Tv data) : data_(std::forwardTv(data)) {}variant() {}~ variant() {}
};variant_alternative
templateint N, typename ...Ts struct variant_alternative {};templateint N, typename ...Ts
struct variant_alternativeN, variantTs...: variant_alternativeN, typename variantTs...::data_type {};templateint N, typename ...Ts
struct variant_alternativeN, __unionTs...: variant_alternativeN - 1, typename __unionTs...::rest_type {};templatetypename ...Ts
struct variant_alternative0, __unionTs... {using type __unionTs...::value_type;
};templateint N, typename ...Ts
using variant_alternative_t variant_alternativeN, Ts...::type;variant_size
templatetypename ...Ts struct variant_size {};templatetypename ...Ts
struct variant_sizevariantTs...: std::integral_constantint, sizeof...(Ts) {};templatetypename ...Ts
constexpr static int variant_size_v variant_sizeTs...::value;get type 、get N
这里的实现并不会像std::variant一样即可以把我们的实现认为就是一个union
get N
templateint N, typename T
struct get_impl {static auto get(T data) {return get_implN - 1, typename T::rest_type::get(data.rest_);}
};templatetypename T
struct get_impl0, T {static T::value_type get(T data) {return data.value_;}
};templateint N, typename T
static auto get(T var) {return get_implN, typename T::data_type::get(var.data_);
}get type
templatetypename T, typename Tv
struct get_type_impl {static auto get(Tv data) {return get_type_implT, typename Tv::rest_type::get(data.rest_);}
};templatetypename Tv
struct get_type_impltypename Tv::value_type, Tv {static Tv::value_type get(Tv data) {return data.value_;}
};templatetypename T, typename Tv
static auto get(Tv var) {return get_type_implT, typename Tv::data_type::get(var.data_);
}operator
这里也是variant最重要的功能了能够在赋值的时候自动析构原来保存的值。
先看不加析构函数的版本:
templatetypename Tv
variant operator (Tv data) {new (data_) data_type(std::forwardTv(data));return *this;
}TEST
struct Test {~ Test() {std::cout ~ Test()\n;}
};Test a, b;
variantint, long long, Test variant_test(a);
std::cout OK\n;
variant_test b;
std::cout OK\n;OK OK ~ Test() ~ Test() 只有最后a、b的两次析构缺少了赋值时和销毁variant时的析构调用。
要能够析构那么势必我们需要保存当前的type为了方便这里直接使用一个int变量来保存type所对应的下标
同时实现一个类模板获取当前值在列表中的位置。
templatetypename Tu, typename T struct type_index_impl: std::integral_constantint, type_index_impltypename Tu::rest_type, T::value 1 {};templatetypename Tu
struct type_index_implTu, typename Tu::value_type: std::integral_constantint, 0 {};templatetypename Tu, typename T
constexpr static int type_index type_index_implTu, T::value;得到所有类型的析构函数由于variant的类型是动态加载的考虑将所有类型的destructor存下来按需调用
std::functionvoid(void *) destructors[sizeof...(Ts)] { [](void *ptr) { static_castTs*(ptr)-~Ts(); }... };接着稍微修改一下operator 、~variant()
templatetypename Tv
variant operator (Tv data) {if (~type_) {destructors[type_](data_);}new (data_) data_type(std::forwardTv(data));type_ type_indexdata_type, std::decay_tTv;return *this;
}~ variant() {if (~type_) {destructors[type_](data_);}
}TEST
struct Test1 {~ Test1() {std::cout ~ Test1()\n;}
}a;struct Test2 {~ Test2() {std::cout ~ Test2()\n;}
}b;variantint, long long, Test1, Test2 variant_test(a);
std::cout OK\n;
variant_test b;
std::cout OK\n;OK Test1() OK Test2() Test2() Test1() Code
#include iostream
#include string
#include type_traits
#include functionaltemplatetypename ...Ts union __union;templatetypename T, typename ...Ts
union __unionT, Ts... {using type __union;using rest_type __unionTs...;using value_type T;T value_;rest_type rest_;templatetypename Tvrequires std::is_same_vstd::decay_tTv, T__union(Tv value) : value_(std::forwardTv(value)) {}template typename Tv__union(Tv rest) : rest_(std::forwardTv(rest)) {}__union() {}~ __union() {}
};templatetypename T
union __unionT {using type __union;using value_type T;T value_;templatetypename Tvrequires std::is_same_vstd::decay_tTv, T__union(Tv value) : value_(std::forwardTv(value)) {}__union() {}~ __union() {}
};templatetypename Tu, typename T struct type_index_impl: std::integral_constantint, type_index_impltypename Tu::rest_type, T::value 1 {};templatetypename Tu
struct type_index_implTu, typename Tu::value_type: std::integral_constantint, 0 {};templatetypename Tu, typename T
constexpr static int type_index type_index_implTu, T::value;templatetypename ...Ts
struct variant {using type variant;using data_type __unionTs...;__unionTs... data_;int type_{-1};std::functionvoid(void *) destructors[sizeof...(Ts)] { [](void *ptr) { static_castTs*(ptr)-~Ts(); }... };templatetypename Tvvariant(Tv data) : data_(std::forwardTv(data)),type_(type_indexdata_type, std::decay_tTv) {}templatetypename Tvvariant operator (Tv data) {if (~type_) {destructors[type_](data_);}new (data_) data_type(std::forwardTv(data));type_ type_indexdata_type, std::decay_tTv;return *this;}variant() {}~ variant() {if (~type_) {destructors[type_](data_);}}
};templateint N, typename ...Ts struct variant_alternative {};templateint N, typename ...Ts
struct variant_alternativeN, variantTs...: variant_alternativeN, typename variantTs...::data_type {};templateint N, typename ...Ts
struct variant_alternativeN, __unionTs...: variant_alternativeN - 1, typename __unionTs...::rest_type {};templatetypename ...Ts
struct variant_alternative0, __unionTs... {using type __unionTs...::value_type;
};templateint N, typename ...Ts
using variant_alternative_t variant_alternativeN, Ts...::type;templatetypename ...Ts struct variant_size {};templatetypename ...Ts
struct variant_sizevariantTs...: std::integral_constantint, sizeof...(Ts) {};templatetypename ...Ts
constexpr static int variant_size_v variant_sizeTs...::value;templateint N, typename T
struct get_n_impl {static auto get(T data) {return get_n_implN - 1, typename T::rest_type::get(data.rest_);}
};templatetypename T
struct get_n_impl0, T {static T::value_type get(T data) {return data.value_;}
};templateint N, typename T
static auto get(T var) {return get_n_implN, typename T::data_type::get(var.data_);
}templatetypename T, typename Tv
struct get_type_impl {static auto get(Tv data) {return get_type_implT, typename Tv::rest_type::get(data.rest_);}
};templatetypename Tv
struct get_type_impltypename Tv::value_type, Tv {static Tv::value_type get(Tv data) {return data.value_;}
};templatetypename T, typename Tv
static auto get(Tv var) {return get_type_implT, typename Tv::data_type::get(var.data_);
}int main() {int a 114;auto u1 __unionshort int, int, unsigned int, long long, float, double(a);std::cout u1.value_ u1.rest_.value_ u1.rest_.rest_.value_ u1.rest_.rest_.rest_.value_ u1.rest_.rest_.rest_.rest_.value_ u1.rest_.rest_.rest_.rest_.rest_.value_ \n;const double b 115.514;auto u2 __unionshort int, int, unsigned int, long long, float, double(b);std::cout u2.value_ u2.rest_.value_ u2.rest_.rest_.value_ u2.rest_.rest_.rest_.value_ u2.rest_.rest_.rest_.rest_.value_ u2.rest_.rest_.rest_.rest_.rest_.value_ \n;std::string str1 lifehappy;auto u3 __unionint, double, std::string(std::move(str1));std::cout u3.value_ u3.rest_.value_ u3.rest_.rest_.value_ : __union\n;std::cout str1 : str\n;auto v3 variantint, double, std::string();std::cout std::is_same_vint, variant_alternative_t0, decltype(v3) std::is_same_vdouble, variant_alternative_t1, decltype(v3) std::is_same_vstd::string, variant_alternative_t2, decltype(v3) \n;std::cout std::is_same_vint, variant_alternative_t0, decltype(u3) std::is_same_vdouble, variant_alternative_t1, decltype(u3) std::is_same_vstd::string, variant_alternative_t2, decltype(u3) \n;std::cout std::is_same_vvariant_alternative_t0, decltype(v3), variant_alternative0, decltype(v3)::type std::is_same_vvariant_alternative_t1, decltype(v3), variant_alternative1, decltype(v3)::type std::is_same_vvariant_alternative_t2, decltype(v3), variant_alternative2, decltype(v3)::type \n;std::cout std::is_same_vvariant_alternative_t0, decltype(u3), variant_alternative0, decltype(u3)::type std::is_same_vvariant_alternative_t1, decltype(u3), variant_alternative1, decltype(u3)::type std::is_same_vvariant_alternative_t2, decltype(u3), variant_alternative2, decltype(u3)::type \n;std::cout variant_sizedecltype(v3)::value variant_size_vdecltype(v3) \n;variantint, unsigned int, long long, double, std::string v4((int)114514);std::cout get_n_impl0, decltype(v4.data_)::get(v4.data_) get_n_impl1, decltype(v4.data_)::get(v4.data_) get_n_impl2, decltype(v4.data_)::get(v4.data_) get_n_impl3, decltype(v4.data_)::get(v4.data_) get_n_impl4, decltype(v4.data_)::get(v4.data_) \n;std::cout get0(v4) get1(v4) get2(v4) get3(v4) get4(v4) \n;std::cout get_type_implint, decltype(v4.data_)::get(v4.data_) get_type_implunsigned int, decltype(v4.data_)::get(v4.data_) get_type_impllong long, decltype(v4.data_)::get(v4.data_) get_type_impldouble, decltype(v4.data_)::get(v4.data_) get_type_implstd::string, decltype(v4.data_)::get(v4.data_) \n;std::cout getint(v4) getunsigned int(v4) getlong long(v4) getdouble(v4) getstd::string(v4) \n;int int1 1;const int int2 1;int int3 int1;std::cout variantint, float, std::string().type_ variantint, float, std::string(int1).type_ variantint, float, std::string(int2).type_ variantint, float, std::string(int3).type_ variantint, float, std::string(1.1f).type_ variantint, float, std::string(std::string(lifehappy)).type_ \n;struct Test1 {~ Test1() {std::cout ~ Test1()\n;}}ta;struct Test2 {~ Test2() {std::cout ~ Test2()\n;}}tb;variantint, long long, Test1, Test2 variant_test(ta);std::cout OK\n;variant_test tb;std::cout OK\n;return 0;
}