mirror of
https://github.com/davisking/dlib.git
synced 2024-11-01 10:14:53 +08:00
[TYPE_SAFE_UNION] upgrade (#2443)
* [TYPE_SAFE_UNION] upgrade * MSVC doesn't like keyword not * MSVC doesn't like keyword and * added tests for emplate(), copy semantics, move semantics, swap, overloaded and apply_to_contents with non void return types * - didn't need is_void anymore - added result_of_t - didn't really need ostream_helper or istream_helper - split apply_to_contents into apply_to_contents (return void) and visit (return anything so long as visitor is publicly accessible) * - updated abstract file * - added get_type_t - removed deserialize_helper dupplicate - don't use std::decay_t, that's c++14 * - removed white spaces - don't need a return-statement when calling apply_to_contents_impl() - use unchecked_get() whenever possible to minimise explicit use of pointer casting. lets keep that to a minimum * - added type_safe_union_size - added type_safe_union_size_v if C++14 is available - added tests for above * - test type_safe_union_size_v * testing nested unions with visitors. * re-added comment * added index() in abstract file * - refactored reset() to clear() - added comment about clear() in abstract file - in deserialize(), only reset the object if necessary * - removed unecessary comment about exceptions - removed unecessary // ------------- - struct is_valid is not mentioned in abstract. Instead rather requiring T to be a valid type, it is ensured! - get_type and get_type_t are private. Client code shouldn't need this. - shuffled some functions around - type_safe_union_size and type_safe_union_size_v are removed. not needed - reset() -> clear() - bug fix in deserialize() index counts from 1, not 0 - improved the abstract file * refactored index() to get_current_type_id() as per suggestion * maybe slightly improved docs * - HURRAY, don't need std::result_of or std::invoke_result for visit() to work. Just privately define your own type trait, in this case called return_type and return_type_t. it works! - apply_to_contents() now always calls visit() * example with private visitor using friendship with non-void return types. * Fix up contracts It can't be a post condition that T is a valid type, since the choice of T is up to the caller, it's not something these functions decide. Making it a precondition. * Update dlib/type_safe_union/type_safe_union_kernel_abstract.h * Update dlib/type_safe_union/type_safe_union_kernel_abstract.h * Update dlib/type_safe_union/type_safe_union_kernel_abstract.h * - added more tests for copy constructors/assignments, move constructors/assignments, and converting constructors/assignments - helper_copy -> helper_forward - added validate_type<T> in a couple of places * - helper_move only takes non-const lvalue references. So we are not using std::move with universal references ! - use enable_if<is_valid<T>> in favor of validate_type<T>() * - use enable_if<is_valid<T>> in favor of validate_type<T>() * - added is_valid_check<>. This wraps enable_if<is_valid<T>,bool> and makes use of SFINAE more robust Co-authored-by: pfeatherstone <peter@me> Co-authored-by: pf <pf@me> Co-authored-by: Davis E. King <davis685@gmail.com>
This commit is contained in:
parent
bf4100069f
commit
2b8f9e401a
@ -429,7 +429,6 @@ namespace
|
||||
b = 3;
|
||||
b = std::move(a);
|
||||
|
||||
DLIB_TEST(a.get<int>() == 3);
|
||||
DLIB_TEST(b.get<std::string>() == "asdf");
|
||||
}
|
||||
|
||||
@ -458,12 +457,215 @@ namespace
|
||||
DLIB_TEST(!a.contains<ptr_t>());
|
||||
DLIB_TEST(*b.get<ptr_t>() == "asdf");
|
||||
}
|
||||
|
||||
{
|
||||
//testing copy semantics and move semantics
|
||||
|
||||
struct mytype
|
||||
{
|
||||
mytype(int i_ = 0) : i(i_) {}
|
||||
|
||||
mytype(const mytype& other) : i(other.i) {}
|
||||
mytype& operator=(const mytype& other) {i = other.i; return *this;}
|
||||
|
||||
mytype(mytype&& other) : i(other.i) {other.i = 0;}
|
||||
mytype& operator=(mytype&& other) {i = other.i ; other.i = 0; return *this;}
|
||||
|
||||
int i = 0;
|
||||
};
|
||||
|
||||
using tsu = type_safe_union<int,mytype>;
|
||||
|
||||
{
|
||||
mytype a(10);
|
||||
tsu ta(a); //copy constructor
|
||||
DLIB_TEST(a.i == 10);
|
||||
DLIB_TEST(ta.cast_to<mytype>().i == 10);
|
||||
}
|
||||
|
||||
{
|
||||
mytype a(10);
|
||||
tsu ta;
|
||||
ta = a; //copy assign
|
||||
DLIB_TEST(a.i == 10);
|
||||
DLIB_TEST(ta.cast_to<mytype>().i == 10);
|
||||
}
|
||||
|
||||
{
|
||||
mytype a(10);
|
||||
tsu ta(std::move(a)); //move constructor
|
||||
DLIB_TEST(a.i == 0);
|
||||
DLIB_TEST(ta.cast_to<mytype>().i == 10);
|
||||
}
|
||||
|
||||
{
|
||||
mytype a(10);
|
||||
tsu ta;
|
||||
ta = std::move(a); //move assign
|
||||
DLIB_TEST(a.i == 0);
|
||||
DLIB_TEST(ta.cast_to<mytype>().i == 10);
|
||||
}
|
||||
|
||||
{
|
||||
tsu ta(mytype(10));
|
||||
DLIB_TEST(ta.cast_to<mytype>().i == 10);
|
||||
tsu tb(ta); //copy constructor
|
||||
DLIB_TEST(ta.cast_to<mytype>().i == 10);
|
||||
DLIB_TEST(tb.cast_to<mytype>().i == 10);
|
||||
}
|
||||
|
||||
{
|
||||
tsu ta(mytype(10));
|
||||
DLIB_TEST(ta.cast_to<mytype>().i == 10);
|
||||
tsu tb;
|
||||
tb = ta; //copy assign
|
||||
DLIB_TEST(ta.cast_to<mytype>().i == 10);
|
||||
DLIB_TEST(tb.cast_to<mytype>().i == 10);
|
||||
}
|
||||
|
||||
{
|
||||
tsu ta(mytype(10));
|
||||
DLIB_TEST(ta.cast_to<mytype>().i == 10);
|
||||
tsu tb(std::move(ta)); //move constructor
|
||||
DLIB_TEST(ta.is_empty());
|
||||
DLIB_TEST(tb.cast_to<mytype>().i == 10);
|
||||
}
|
||||
|
||||
{
|
||||
tsu ta(mytype(10));
|
||||
DLIB_TEST(ta.cast_to<mytype>().i == 10);
|
||||
tsu tb;
|
||||
tb = std::move(ta); //move assign
|
||||
DLIB_TEST(ta.is_empty());
|
||||
DLIB_TEST(tb.cast_to<mytype>().i == 10);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
//testing emplace(), copy semantics, move semantics, swap, overloaded, and new visitor
|
||||
type_safe_union<int, float, std::string> a, b;
|
||||
a.emplace<std::string>("hello world");
|
||||
|
||||
DLIB_TEST(a.contains<std::string>());
|
||||
b = a; //copy
|
||||
DLIB_TEST(a.contains<std::string>());
|
||||
DLIB_TEST(b.contains<std::string>());
|
||||
DLIB_TEST(a.cast_to<std::string>() == "hello world");
|
||||
DLIB_TEST(b.cast_to<std::string>() == "hello world");
|
||||
a = 1;
|
||||
DLIB_TEST(a.contains<int>());
|
||||
DLIB_TEST(a.cast_to<int>() == 1);
|
||||
b = std::move(a);
|
||||
DLIB_TEST(b.contains<int>());
|
||||
DLIB_TEST(b.cast_to<int>() == 1);
|
||||
DLIB_TEST(a.is_empty());
|
||||
DLIB_TEST(a.get_current_type_id() == 0);
|
||||
swap(a, b);
|
||||
DLIB_TEST(a.contains<int>());
|
||||
DLIB_TEST(a.cast_to<int>() == 1);
|
||||
DLIB_TEST(b.is_empty());
|
||||
DLIB_TEST(b.get_current_type_id() == 0);
|
||||
//visit can return non-void types
|
||||
auto ret = a.visit(overloaded(
|
||||
[](int) {
|
||||
return std::string("int");
|
||||
},
|
||||
[](float) {
|
||||
return std::string("float");
|
||||
},
|
||||
[](const std::string&) {
|
||||
return std::string("std::string");
|
||||
}
|
||||
));
|
||||
static_assert(std::is_same<std::string, decltype(ret)>::value, "bad return type");
|
||||
DLIB_TEST(ret == "int");
|
||||
//apply_to_contents can only return void
|
||||
a = std::string("hello there!");
|
||||
std::string str;
|
||||
a.apply_to_contents(overloaded(
|
||||
[&str](int) {
|
||||
str = std::string("int");
|
||||
},
|
||||
[&str](float) {
|
||||
str = std::string("float");
|
||||
},
|
||||
[&str](const std::string& item) {
|
||||
str = item;
|
||||
}
|
||||
));
|
||||
DLIB_TEST(str == "hello there!");
|
||||
}
|
||||
|
||||
{
|
||||
//nested unions
|
||||
using tsu_a = type_safe_union<int,float,std::string>;
|
||||
using tsu_b = type_safe_union<int,float,std::string,tsu_a>;
|
||||
|
||||
tsu_b object(dlib::in_place_tag<tsu_a>{}, std::string("hello from bottom node"));
|
||||
DLIB_TEST(object.contains<tsu_a>());
|
||||
DLIB_TEST(object.get<tsu_a>().get<std::string>() == "hello from bottom node");
|
||||
auto ret = object.visit(overloaded(
|
||||
[](int) {
|
||||
return std::string("int");
|
||||
},
|
||||
[](float) {
|
||||
return std::string("float");
|
||||
},
|
||||
[](std::string) {
|
||||
return std::string("std::string");
|
||||
},
|
||||
[](const tsu_a& item) {
|
||||
return item.visit(overloaded(
|
||||
[](int) {
|
||||
return std::string("nested int");
|
||||
},
|
||||
[](float) {
|
||||
return std::string("nested float");
|
||||
},
|
||||
[](std::string str) {
|
||||
return str;
|
||||
}
|
||||
));
|
||||
}
|
||||
));
|
||||
static_assert(std::is_same<std::string, decltype(ret)>::value, "bad type");
|
||||
DLIB_TEST(ret == "hello from bottom node");
|
||||
}
|
||||
|
||||
{
|
||||
//"private" visitor
|
||||
using tsu = type_safe_union<int,float,std::string>;
|
||||
|
||||
class visitor_private
|
||||
{
|
||||
private:
|
||||
std::string operator()(int)
|
||||
{
|
||||
return std::string("int");
|
||||
}
|
||||
|
||||
std::string operator()(float)
|
||||
{
|
||||
return std::string("float");
|
||||
}
|
||||
|
||||
std::string operator()(const std::string& str)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
friend tsu;
|
||||
};
|
||||
|
||||
visitor_private visitor;
|
||||
tsu a = std::string("hello from private visitor");
|
||||
auto ret = a.visit(visitor);
|
||||
static_assert(std::is_same<std::string, decltype(ret)>::value, "bad type");
|
||||
DLIB_TEST(ret == "hello from private visitor");
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
class type_safe_union_tester : public tester
|
||||
{
|
||||
public:
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,9 +3,6 @@
|
||||
#undef DLIB_TYPE_SAFE_UNION_KERNEl_ABSTRACT_
|
||||
#ifdef DLIB_TYPE_SAFE_UNION_KERNEl_ABSTRACT_
|
||||
|
||||
#include "../algs.h"
|
||||
#include "../noncopyable.h"
|
||||
|
||||
namespace dlib
|
||||
{
|
||||
|
||||
@ -21,29 +18,31 @@ namespace dlib
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <
|
||||
typename T1,
|
||||
typename T2 = _void, // _void indicates parameter not used.
|
||||
typename T3 = _void,
|
||||
typename T4 = _void,
|
||||
typename T5 = _void,
|
||||
typename T6 = _void,
|
||||
typename T7 = _void,
|
||||
typename T8 = _void,
|
||||
typename T9 = _void,
|
||||
typename T10 = _void,
|
||||
typename T11 = _void,
|
||||
typename T12 = _void,
|
||||
typename T13 = _void,
|
||||
typename T14 = _void,
|
||||
typename T15 = _void,
|
||||
typename T16 = _void,
|
||||
typename T17 = _void,
|
||||
typename T18 = _void,
|
||||
typename T19 = _void,
|
||||
typename T20 = _void
|
||||
>
|
||||
class type_safe_union : noncopyable
|
||||
template<typename T>
|
||||
struct in_place_tag {};
|
||||
/*!
|
||||
This is an empty class type used as a special disambiguation tag to be
|
||||
passed as the first argument to the constructor of type_safe_union that performs
|
||||
in-place construction of an object.
|
||||
|
||||
Here is an example of its usage:
|
||||
|
||||
struct A
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
A(int i_, int j_) : i(i_), j(j_) {}
|
||||
};
|
||||
|
||||
using tsu = type_safe_union<A,std::string>;
|
||||
|
||||
tsu a(in_place_tag<A>{}, 0, 1);
|
||||
!*/
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template <typename... Types>
|
||||
class type_safe_union
|
||||
{
|
||||
/*!
|
||||
REQUIREMENTS ON ALL TEMPLATE ARGUMENTS
|
||||
@ -71,53 +70,91 @@ namespace dlib
|
||||
|
||||
public:
|
||||
|
||||
typedef T1 type1;
|
||||
typedef T2 type2;
|
||||
typedef T3 type3;
|
||||
typedef T4 type4;
|
||||
typedef T5 type5;
|
||||
typedef T6 type6;
|
||||
typedef T7 type7;
|
||||
typedef T8 type8;
|
||||
typedef T9 type9;
|
||||
typedef T10 type10;
|
||||
typedef T11 type11;
|
||||
typedef T12 type12;
|
||||
typedef T13 type13;
|
||||
typedef T14 type14;
|
||||
typedef T15 type15;
|
||||
typedef T16 type16;
|
||||
typedef T17 type17;
|
||||
typedef T18 type18;
|
||||
typedef T19 type19;
|
||||
typedef T20 type20;
|
||||
|
||||
type_safe_union(
|
||||
);
|
||||
) = default;
|
||||
/*!
|
||||
ensures
|
||||
- this object is properly initialized
|
||||
!*/
|
||||
|
||||
template <typename T>
|
||||
type_safe_union (
|
||||
const type_safe_union& item
|
||||
)
|
||||
/*!
|
||||
ensures
|
||||
- copy constructs *this from item
|
||||
!*/
|
||||
|
||||
type_safe_union& operator=(
|
||||
const type_safe_union& item
|
||||
);
|
||||
/*!
|
||||
ensures
|
||||
- copy assigns *this from item
|
||||
!*/
|
||||
|
||||
type_safe_union (
|
||||
type_safe_union&& item
|
||||
);
|
||||
/*!
|
||||
ensures
|
||||
- move constructs *this from item.
|
||||
!*/
|
||||
|
||||
type_safe_union& operator= (
|
||||
type_safe_union&& item
|
||||
);
|
||||
/*!
|
||||
ensures
|
||||
- move assigns *this from item.
|
||||
!*/
|
||||
|
||||
template <
|
||||
typename T
|
||||
>
|
||||
type_safe_union (
|
||||
T&& item
|
||||
);
|
||||
/*!
|
||||
requires
|
||||
- T must be one of the types given to this object's template arguments
|
||||
- std::decay_t<T> must be one of the types given to this object's template arguments
|
||||
ensures
|
||||
- this object is properly initialized
|
||||
- #get<T>() == item
|
||||
(i.e. this object will contain a copy of item, or we move item if it's an rvalue)
|
||||
- constructs *this from item using perfect forwarding (converting constructor)
|
||||
- #get<T>() == std::forward<T>(item)
|
||||
(i.e. this object will either contain a copy of item or will have moved item into *this
|
||||
depending on the reference type)
|
||||
!*/
|
||||
|
||||
type_safe_union (
|
||||
type_safe_union&& item
|
||||
);
|
||||
template <
|
||||
typename T
|
||||
>
|
||||
type_safe_union& operator= (
|
||||
T&& item
|
||||
);
|
||||
/*!
|
||||
requires
|
||||
- std::decay_t<T> must be one of the types given to this object's template arguments
|
||||
ensures
|
||||
- move constructs *this from item.
|
||||
- assigns *this from item using perfect forwarding (converting assignment)
|
||||
- #get<T> == std::forward<T>(item)
|
||||
(i.e. this object will either contain a copy of item or will have moved item into *this
|
||||
depending on the reference type)
|
||||
!*/
|
||||
|
||||
template <
|
||||
typename T,
|
||||
typename... Args
|
||||
>
|
||||
type_safe_union (
|
||||
in_place_tag<T>,
|
||||
Args&&... args
|
||||
);
|
||||
/*!
|
||||
requires
|
||||
- T must be one of the types given to this object's template arguments
|
||||
ensures
|
||||
- constructs *this with type T using constructor-arguments args...
|
||||
(i.e. efficiently performs *this = T(args...))
|
||||
!*/
|
||||
|
||||
~type_safe_union(
|
||||
@ -127,14 +164,36 @@ namespace dlib
|
||||
- all resources associated with this object have been freed
|
||||
!*/
|
||||
|
||||
void clear();
|
||||
/*!
|
||||
ensures
|
||||
- all resources associated with this object have been freed
|
||||
- #is_empty() == true
|
||||
!*/
|
||||
|
||||
template <
|
||||
typename T,
|
||||
typename... Args
|
||||
>
|
||||
void emplace(
|
||||
Args&&... args
|
||||
);
|
||||
/*!
|
||||
requires
|
||||
- T must be one of the types given to this object's template arguments
|
||||
ensures
|
||||
- re-assigns *this with type T using constructor-arguments args...
|
||||
(i.e. efficiently performs *this = T(args...))
|
||||
!*/
|
||||
|
||||
template <typename T>
|
||||
static int get_type_id (
|
||||
static constexpr int get_type_id (
|
||||
);
|
||||
/*!
|
||||
ensures
|
||||
- if (T is the same type as one of the template arguments) then
|
||||
- returns a number indicating which template argument it is.
|
||||
(e.g. if T is the same type as T3 then this function returns 3)
|
||||
- returns a number indicating which template argument it is. In particular,
|
||||
if it's the first template argument it returns 1, if the second then 2, and so on.
|
||||
- else
|
||||
- returns -1
|
||||
!*/
|
||||
@ -160,68 +219,64 @@ namespace dlib
|
||||
- returns false
|
||||
!*/
|
||||
|
||||
template <typename T>
|
||||
void apply_to_contents (
|
||||
T& obj
|
||||
int get_current_type_id(
|
||||
) const;
|
||||
/*!
|
||||
ensures
|
||||
- returns type_identity, i.e, the index of the currently held type.
|
||||
For example if the current type is the first template argument it returns 1, if it's the second then 2, and so on.
|
||||
If the current object is empty, i.e. is_empty() == true, then
|
||||
- returns 0
|
||||
!*/
|
||||
|
||||
template <typename F>
|
||||
auto visit(
|
||||
F&& f
|
||||
);
|
||||
/*!
|
||||
requires
|
||||
- obj is a function object capable of operating on all the types contained
|
||||
in this type_safe_union. I.e. obj(this->get<U>()) must be a valid
|
||||
- f is a callable object capable of operating on all the types contained
|
||||
in this type_safe_union. I.e. std::forward<F>(f)(this->get<U>()) must be a valid
|
||||
expression for all the possible U types.
|
||||
ensures
|
||||
- if (is_empty() == false) then
|
||||
- Let U denote the type of object currently contained in this type_safe_union
|
||||
- calls obj(this->get<U>())
|
||||
- The object returned by this->get<U>() will be non-const
|
||||
- returns std::forward<F>(f)(this->get<U>())
|
||||
- The object passed to f() (i.e. by this->get<U>()) will be non-const.
|
||||
!*/
|
||||
|
||||
template <typename T>
|
||||
void apply_to_contents (
|
||||
const T& obj
|
||||
template <typename F>
|
||||
auto visit(
|
||||
F&& f
|
||||
) const;
|
||||
/*!
|
||||
requires
|
||||
- f is a callable object capable of operating on all the types contained
|
||||
in this type_safe_union. I.e. std::forward<F>(f)(this->get<U>()) must be a valid
|
||||
expression for all the possible U types.
|
||||
ensures
|
||||
- if (is_empty() == false) then
|
||||
- Let U denote the type of object currently contained in this type_safe_union
|
||||
- returns std::forward<F>(f)(this->get<U>())
|
||||
- The object passed to f() (i.e. by this->get<U>()) will be const.
|
||||
!*/
|
||||
|
||||
template <typename F>
|
||||
void apply_to_contents(
|
||||
F&& f
|
||||
);
|
||||
/*!
|
||||
requires
|
||||
- obj is a function object capable of operating on all the types contained
|
||||
in this type_safe_union. I.e. obj(this->get<U>()) must be a valid
|
||||
expression for all the possible U types.
|
||||
ensures
|
||||
- if (is_empty() == false) then
|
||||
- Let U denote the type of object currently contained in this type_safe_union
|
||||
- calls obj(this->get<U>())
|
||||
- The object returned by this->get<U>() will be non-const
|
||||
ensures:
|
||||
equivalent to calling visit(std::forward<F>(f)) with void return type
|
||||
!*/
|
||||
|
||||
template <typename T>
|
||||
void apply_to_contents (
|
||||
T& obj
|
||||
template <typename F>
|
||||
void apply_to_contents(
|
||||
F&& f
|
||||
) const;
|
||||
/*!
|
||||
requires
|
||||
- obj is a function object capable of operating on all the types contained
|
||||
in this type_safe_union. I.e. obj(this->get<U>()) must be a valid
|
||||
expression for all the possible U types.
|
||||
ensures
|
||||
- if (is_empty() == false) then
|
||||
- Let U denote the type of object currently contained in this type_safe_union
|
||||
- calls obj(this->get<U>())
|
||||
- The object returned by this->get<U>() will be const
|
||||
!*/
|
||||
|
||||
template <typename T>
|
||||
void apply_to_contents (
|
||||
const T& obj
|
||||
) const;
|
||||
/*!
|
||||
requires
|
||||
- obj is a function object capable of operating on all the types contained
|
||||
in this type_safe_union. I.e. obj(this->get<U>()) must be a valid
|
||||
expression for all the possible U types.
|
||||
ensures
|
||||
- if (is_empty() == false) then
|
||||
- Let U denote the type of object currently contained in this type_safe_union
|
||||
- calls obj(this->get<U>())
|
||||
- The object returned by this->get<U>() will be const
|
||||
ensures:
|
||||
equivalent to calling visit(std::forward<F>(f)) with void return type
|
||||
!*/
|
||||
|
||||
template <typename T>
|
||||
@ -268,28 +323,6 @@ namespace dlib
|
||||
- throws bad_type_safe_union_cast
|
||||
!*/
|
||||
|
||||
template <typename T>
|
||||
type_safe_union& operator= (
|
||||
T&& item
|
||||
);
|
||||
/*!
|
||||
requires
|
||||
- T must be one of the types given to this object's template arguments
|
||||
ensures
|
||||
- #get<T>() == item
|
||||
(i.e. this object will contain a copy of item, or we move item if it's an rvalue)
|
||||
- returns *this
|
||||
!*/
|
||||
|
||||
type_safe_union& operator= (
|
||||
type_safe_union&& item
|
||||
);
|
||||
/*!
|
||||
ensures
|
||||
- Allows moving item into *this. In fact, this is done by this->swap(item).
|
||||
- returns *this
|
||||
!*/
|
||||
|
||||
void swap (
|
||||
type_safe_union& item
|
||||
);
|
||||
@ -340,7 +373,51 @@ namespace dlib
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
template<typename... T>
|
||||
overloaded_helper<typename std::decay<T>::type...> overloaded(T&&... t)
|
||||
{
|
||||
return overloaded_helper<typename std::decay<T>::type...>{std::forward<T>(t)...};
|
||||
}
|
||||
/*!
|
||||
This is a helper function for passing many callable objects (usually lambdas)
|
||||
to either apply_to_contents() or visit(), that combine to make a complete
|
||||
visitor. A picture paints a thousand words:
|
||||
|
||||
using tsu = type_safe_union<int,float,std::string>;
|
||||
|
||||
tsu a = std::string("hello there");
|
||||
|
||||
std::string result;
|
||||
|
||||
a.apply_to_contents(overloaded(
|
||||
[&result](int) {
|
||||
result = std::string("int");
|
||||
},
|
||||
[&result](float) {
|
||||
result = std::string("float");
|
||||
},
|
||||
[&result](const std::string& item) {
|
||||
result = item;
|
||||
}
|
||||
));
|
||||
|
||||
assert(result == "hello there");
|
||||
result = "";
|
||||
|
||||
result = a.visit(overloaded(
|
||||
[](int) {
|
||||
return std::string("int");
|
||||
},
|
||||
[](float) {
|
||||
return std::string("float");
|
||||
},
|
||||
[](const std::string& item) {
|
||||
return item;
|
||||
}
|
||||
));
|
||||
|
||||
assert(result == "hello there");
|
||||
!*/
|
||||
}
|
||||
|
||||
#endif // DLIB_TYPE_SAFE_UNION_KERNEl_ABSTRACT_
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user