mirror of
https://github.com/ETLCPP/etl.git
synced 2026-06-16 00:46:03 +08:00
Feature/variant visit (#552)
* add variant visit to c++11 and above * visit legacy added * update with multiple variants visit for variadic
This commit is contained in:
parent
8669afec86
commit
89be7e62cf
@ -94,6 +94,17 @@ namespace etl
|
||||
}
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// 'Bad variant access' exception for the variant class.
|
||||
///\ingroup variant
|
||||
//***************************************************************************
|
||||
class bad_variant_access : public variant_exception {
|
||||
public:
|
||||
bad_variant_access(string_type file_name_, numeric_type line_number_)
|
||||
: variant_exception(ETL_ERROR_TEXT("variant:bad variant access", ETL_VARIANT_FILE_ID"A"), file_name_, line_number_)
|
||||
{}
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// A template class that can store any of the types defined in the template parameter list.
|
||||
/// Supports up to 8 types.
|
||||
@ -1057,4 +1068,98 @@ namespace etl
|
||||
//***************************************************************************
|
||||
type_id_t type_id;
|
||||
};
|
||||
|
||||
namespace private_variant
|
||||
{
|
||||
template <size_t, typename>
|
||||
struct variant_alternative_helper;
|
||||
#define ETL_VARIANT_HELPER(INDEX, TYPE) \
|
||||
template <typename T1, \
|
||||
typename T2, \
|
||||
typename T3, \
|
||||
typename T4, \
|
||||
typename T5, \
|
||||
typename T6, \
|
||||
typename T7, \
|
||||
typename T8> \
|
||||
struct variant_alternative_helper<INDEX, variant<T1, T2, T3, T4, T5, T6, T7, T8>> \
|
||||
{ \
|
||||
typedef TYPE type; \
|
||||
};
|
||||
ETL_VARIANT_HELPER(0, T1)
|
||||
ETL_VARIANT_HELPER(1, T2)
|
||||
ETL_VARIANT_HELPER(2, T3)
|
||||
ETL_VARIANT_HELPER(3, T4)
|
||||
ETL_VARIANT_HELPER(4, T5)
|
||||
ETL_VARIANT_HELPER(5, T6)
|
||||
ETL_VARIANT_HELPER(6, T7)
|
||||
ETL_VARIANT_HELPER(7, T8)
|
||||
#undef ETL_VARIANT_HELPER
|
||||
} // namespace private_variant
|
||||
template <size_t tIndex, typename TVariant>
|
||||
struct variant_alternative
|
||||
{
|
||||
typedef typename private_variant::variant_alternative_helper<tIndex, TVariant>::type type;
|
||||
};
|
||||
template <size_t tIndex, typename TVariant>
|
||||
struct variant_alternative<tIndex, TVariant const>
|
||||
{
|
||||
typedef typename private_variant::variant_alternative_helper<tIndex, TVariant>::type const type;
|
||||
};
|
||||
template <size_t tIndex, typename TVariant>
|
||||
struct variant_alternative<tIndex, TVariant volatile>
|
||||
{
|
||||
typedef typename private_variant::variant_alternative_helper<tIndex, TVariant>::type volatile type;
|
||||
};
|
||||
template <size_t tIndex, typename TVariant>
|
||||
struct variant_alternative<tIndex, TVariant const volatile>
|
||||
{
|
||||
typedef typename private_variant::variant_alternative_helper<tIndex, TVariant>::type const volatile type;
|
||||
};
|
||||
template <typename T, typename TVariant>
|
||||
inline T& get(TVariant& variant)
|
||||
{
|
||||
return variant.template get<T>();
|
||||
}
|
||||
template <typename T, typename TVariant>
|
||||
inline T const& get(TVariant const& variant)
|
||||
{
|
||||
return variant.template get<T>();
|
||||
}
|
||||
template <size_t tIndex, typename TVariant>
|
||||
inline typename variant_alternative<tIndex, TVariant>::type& get(TVariant& variant)
|
||||
{
|
||||
return get<typename variant_alternative<tIndex, TVariant>::type>(variant);
|
||||
}
|
||||
template <size_t tIndex, typename TVariant>
|
||||
inline typename variant_alternative<tIndex, TVariant const>::type& get(TVariant const& variant)
|
||||
{
|
||||
return get<typename variant_alternative<tIndex, TVariant>::type>(variant);
|
||||
}
|
||||
|
||||
#define ETL_GEN_LEGACY_VISIT(VISITQUAL, VARIANTQUAL) \
|
||||
template <typename TRet, typename TVisitor, typename TVariant> \
|
||||
static TRet visit(TVisitor VISITQUAL visitor, TVariant VARIANTQUAL variant) \
|
||||
{ \
|
||||
switch (variant.index()) \
|
||||
{ \
|
||||
case 0: return static_cast<TRet>(visitor(get<0>(variant))); \
|
||||
case 1: return static_cast<TRet>(visitor(get<1>(variant))); \
|
||||
case 2: return static_cast<TRet>(visitor(get<2>(variant))); \
|
||||
case 3: return static_cast<TRet>(visitor(get<3>(variant))); \
|
||||
case 4: return static_cast<TRet>(visitor(get<4>(variant))); \
|
||||
case 5: return static_cast<TRet>(visitor(get<5>(variant))); \
|
||||
case 6: return static_cast<TRet>(visitor(get<6>(variant))); \
|
||||
case 7: return static_cast<TRet>(visitor(get<7>(variant))); \
|
||||
default: ETL_ASSERT(false, ETL_ERROR(bad_variant_access)); \
|
||||
} \
|
||||
}
|
||||
|
||||
ETL_GEN_LEGACY_VISIT(&, &)
|
||||
ETL_GEN_LEGACY_VISIT(const&, &)
|
||||
ETL_GEN_LEGACY_VISIT(&, const&)
|
||||
ETL_GEN_LEGACY_VISIT(const&, const&)
|
||||
|
||||
#undef ETL_GEN_LEGACY_VISIT
|
||||
|
||||
}
|
||||
|
||||
@ -426,6 +426,17 @@ namespace etl
|
||||
}
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// 'Bad variant access' exception for the variant class.
|
||||
///\ingroup variant
|
||||
//***************************************************************************
|
||||
class bad_variant_access : public variant_exception {
|
||||
public:
|
||||
bad_variant_access(string_type file_name_, numeric_type line_number_)
|
||||
: variant_exception(ETL_ERROR_TEXT("variant:bad variant access", ETL_VARIANT_FILE_ID"A"), file_name_, line_number_)
|
||||
{}
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// A template class that can store any of the types defined in the template parameter list.
|
||||
/// Supports up to 8 types.
|
||||
@ -1265,5 +1276,189 @@ namespace etl
|
||||
template <typename... TTypes>
|
||||
inline constexpr size_t variant_size_v = variant_size<TTypes...>::value;
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
/// visit
|
||||
//***************************************************************************
|
||||
namespace private_variant
|
||||
{
|
||||
//***************************************************************************
|
||||
/// Deduces return type of a call to TCallable with arguments Ts.
|
||||
/// A lite version of std::invoke_result.
|
||||
//***************************************************************************
|
||||
template <typename TCallable, typename... Ts>
|
||||
struct single_visit_result_type
|
||||
{
|
||||
using type = decltype(std::declval<TCallable>()(std::declval<Ts>()...));
|
||||
};
|
||||
template <typename TCallable, typename... Ts>
|
||||
using single_visit_result_type_t = typename single_visit_result_type<TCallable, Ts...>::type;
|
||||
|
||||
//***************************************************************************
|
||||
/// Used to copy r/l value reference qualifier from a variant type to an
|
||||
/// element.
|
||||
//***************************************************************************
|
||||
template <typename TVar, typename T>
|
||||
using rlref_copy = conditional_t<is_reference<TVar>::value, T&, T&&>;
|
||||
|
||||
//***************************************************************************
|
||||
/// Evaluates all permutations of calls to a callable object that can be done
|
||||
/// based upon the variants input. Need a `index_sequence<...>` as second
|
||||
/// argument that contains all possible indices of the first following variant.
|
||||
/// The first argument is essentially a `single_visit_result_type`-prototype
|
||||
/// in which every recursive instantiation of `visit_result_helper` appends
|
||||
/// more elements and give it a pass through `common_type_t`.
|
||||
//***************************************************************************
|
||||
template <template <typename...> typename, typename...>
|
||||
struct visit_result_helper;
|
||||
template <template <typename...> typename TToInject, size_t... tAltIndices, typename TCur>
|
||||
struct visit_result_helper<TToInject, index_sequence<tAltIndices...>, TCur>
|
||||
{
|
||||
template <size_t tIndex>
|
||||
using var_type = rlref_copy<TCur,
|
||||
variant_alternative_t<tIndex, remove_reference_t<TCur> > >;
|
||||
|
||||
using type = common_type_t<TToInject<var_type<tAltIndices> >...>;
|
||||
};
|
||||
template <template <typename...> typename TToInject, size_t... tAltIndices, typename TCur, typename TNext, typename... TVs>
|
||||
struct visit_result_helper<TToInject, index_sequence<tAltIndices...>, TCur, TNext, TVs...>
|
||||
{
|
||||
template <size_t tIndex>
|
||||
using var_type = rlref_copy<TCur, variant_alternative_t<tIndex, remove_reference_t<TCur> > >;
|
||||
|
||||
template <size_t tIndex>
|
||||
struct next_inject_wrap
|
||||
{
|
||||
template <typename... TNextInj>
|
||||
using next_inject = TToInject<var_type<tIndex>, TNextInj...>;
|
||||
using recursive_result = typename visit_result_helper<next_inject, make_index_sequence<variant_size<remove_reference_t<TNext> >::value>, TNext, TVs...>::type;
|
||||
};
|
||||
using type = common_type_t<typename next_inject_wrap<tAltIndices>::recursive_result...>;
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// Used to create a template alias that has the TCallable embedded into the
|
||||
/// first argument.
|
||||
//***************************************************************************
|
||||
template <typename TCallable>
|
||||
struct visit_result_single_wrapper
|
||||
{
|
||||
template <typename... Ts>
|
||||
using ttype = single_visit_result_type_t<TCallable, Ts...>;
|
||||
};
|
||||
|
||||
template <typename TCallable, typename T1, typename... Ts>
|
||||
struct visit_result
|
||||
{
|
||||
using type = typename visit_result_helper<typename visit_result_single_wrapper<TCallable>::ttype, make_index_sequence<variant_size<remove_reference_t<T1> >::value>, T1, Ts...>::type;
|
||||
};
|
||||
|
||||
template <typename TCallable, typename... Ts>
|
||||
using visit_result_t = typename visit_result<TCallable, Ts...>::type;
|
||||
|
||||
//***************************************************************************
|
||||
/// Makes a call to TCallable using tIndex alternative to the variant.
|
||||
/// Instantiated as function pointer in the `do_visit` function.
|
||||
//***************************************************************************
|
||||
template <typename TRet, typename TCallable, typename TVariant, size_t tIndex>
|
||||
constexpr TRet do_visit_single(TCallable&& f, TVariant&& v)
|
||||
{
|
||||
return static_cast<TCallable&&>(f)(etl::get<tIndex>(static_cast<TVariant&&>(v)));
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Helper to instantiate the function pointers needed for the "jump table".
|
||||
/// Embedds the 'TVarRest' (remaining variants) into its type to come around
|
||||
/// the "double expansion" otherwise needed in "do_visit".
|
||||
//***************************************************************************
|
||||
template <typename TRet, typename TCallable, typename TCurVariant, typename... TVarRest>
|
||||
struct do_visit_helper
|
||||
{
|
||||
using function_pointer = add_pointer_t<TRet(TCallable&&, TCurVariant&&, TVarRest&&...)>;
|
||||
template <size_t tIndex>
|
||||
static constexpr function_pointer fptr() noexcept
|
||||
{
|
||||
return &do_visit_single<TRet, TCallable, TCurVariant, tIndex, TVarRest...>;
|
||||
}
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// Dispatch current variant into recursive calls to dispatch the rest.
|
||||
//***************************************************************************
|
||||
template <typename TRet, typename TCallable, typename TVariant, size_t... tIndices, typename... TVarRest>
|
||||
ETL_CONSTEXPR14 static TRet do_visit(TCallable&& f, TVariant&& v, index_sequence<tIndices...>, TVarRest&&... variants)
|
||||
{
|
||||
ETL_ASSERT(!v.valueless_by_exception(), ETL_ERROR(bad_variant_access));
|
||||
using helper_t = do_visit_helper<TRet, TCallable, TVariant, TVarRest...>;
|
||||
using func_ptr = typename helper_t::function_pointer;
|
||||
constexpr func_ptr jmp_table[]{
|
||||
helper_t::template fptr<tIndices>()...};
|
||||
return jmp_table[v.index()](static_cast<TCallable&&>(f), static_cast<TVariant&&>(v), static_cast<TVarRest&&>(variants)...);
|
||||
}
|
||||
|
||||
template <typename TRet, typename TCallable, typename TVariant, typename... TVs>
|
||||
ETL_CONSTEXPR14 static TRet visit(TCallable&& f, TVariant&& v, TVs&&... vs)
|
||||
{
|
||||
constexpr size_t variants = etl::variant_size<typename remove_reference<TVariant>::type>::value;
|
||||
return private_variant::do_visit<TRet>(static_cast<TCallable&&>(f),
|
||||
static_cast<TVariant&&>(v),
|
||||
make_index_sequence<variants>{},
|
||||
static_cast<TVs&&>(vs)...);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Allows constexpr operation in c++14, otherwise acts like a lambda to
|
||||
/// bind a variant "get" to an argument for "TCallable".
|
||||
//***************************************************************************
|
||||
template <typename TRet, typename TCallable, typename TVariant, size_t tIndex>
|
||||
class constexpr_visit_closure
|
||||
{
|
||||
add_pointer_t<TCallable> callable_;
|
||||
add_pointer_t<TVariant> variant_;
|
||||
|
||||
public:
|
||||
constexpr constexpr_visit_closure(TCallable&& c, TVariant&& v)
|
||||
: callable_(&c), variant_(&v)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
ETL_CONSTEXPR14 TRet operator()(Ts&&... args) const
|
||||
{
|
||||
return static_cast<TCallable&&>(*callable_)(get<tIndex>(static_cast<TVariant&&>(*variant_)), static_cast<Ts&&>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TRet, typename TCallable, typename TVariant, size_t tIndex, typename... TVariants>
|
||||
ETL_CONSTEXPR14 static TRet do_visit_single(TCallable&& f, TVariant&& v, TVariants&&... vs)
|
||||
{
|
||||
return private_variant::visit<TRet>(constexpr_visit_closure<TRet, TCallable, TVariant, tIndex>(static_cast<TCallable&&>(f), static_cast<TVariant&&>(v)),
|
||||
static_cast<TVariants&&>(vs)...);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Dummy-struct used to indicate that the return type should be auto-deduced
|
||||
/// from the callable object and the alternatives in the variants passed to
|
||||
/// a visit. Should never explicitly be used by an user.
|
||||
//***************************************************************************
|
||||
struct visit_auto_return
|
||||
{
|
||||
};
|
||||
|
||||
template <typename TRet, typename TCallable, typename... TVariants>
|
||||
using visit_return = conditional_t<is_same<TRet, visit_auto_return>::value, visit_result_t<TCallable&&, TVariants&&...>, TRet>;
|
||||
|
||||
} // namespace private_variant
|
||||
|
||||
//***************************************************************************
|
||||
/// c++11/14 compatible etl::visit for etl::variant. Supports both c++17
|
||||
/// "auto return type" signature
|
||||
//***************************************************************************
|
||||
template <typename TRet = private_variant::visit_auto_return, typename... TVariants, typename TCallable, typename TDeducedReturn = private_variant::visit_return<TRet, TCallable, TVariants...> >
|
||||
ETL_CONSTEXPR14 static TDeducedReturn visit(TCallable&& f, TVariants&&... vs)
|
||||
{
|
||||
return private_variant::visit<TDeducedReturn>(static_cast<TCallable&&>(f), static_cast<TVariants&&>(vs)...);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -791,5 +791,79 @@ namespace
|
||||
CHECK(variant.is_type<D4>());
|
||||
CHECK_EQUAL(D4("1", "2", "3", "4"), variant.get<D4>());
|
||||
}
|
||||
|
||||
struct variant_test_visit_dispatcher {
|
||||
// const overloads
|
||||
int8_t operator()(int8_t&) const {
|
||||
return 1;
|
||||
}
|
||||
int8_t operator()(int8_t const&) const {
|
||||
return 10;
|
||||
}
|
||||
int8_t operator()(uint8_t&) const {
|
||||
return 2;
|
||||
}
|
||||
int8_t operator()(uint8_t const&) const {
|
||||
return 20;
|
||||
}
|
||||
int8_t operator()(int16_t&) const {
|
||||
return 3;
|
||||
}
|
||||
int8_t operator()(int16_t const&) const {
|
||||
return 30;
|
||||
}
|
||||
|
||||
// non-const overloads
|
||||
int8_t operator()(int8_t&) {
|
||||
return 5;
|
||||
}
|
||||
int8_t operator()(int8_t const&) {
|
||||
return 50;
|
||||
}
|
||||
int8_t operator()(uint8_t&) {
|
||||
return 6;
|
||||
}
|
||||
int8_t operator()(uint8_t const&) {
|
||||
return 60;
|
||||
}
|
||||
int8_t operator()(int16_t&) {
|
||||
return 7;
|
||||
}
|
||||
int8_t operator()(int16_t const&) {
|
||||
return 70;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
int8_t operator()(T const&) const {
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
//*************************************************************************
|
||||
TEST(TestVariantVisit)
|
||||
{
|
||||
test_variant_3 variant;
|
||||
variant = int8_t{};
|
||||
// c++98 should generate a const ref of dispatchern.
|
||||
int16_t type = etl::visit<int16_t>(variant_test_visit_dispatcher{}, variant);
|
||||
CHECK_EQUAL(1, type);
|
||||
test_variant_3 const& variant_const = variant;
|
||||
type = etl::visit<int16_t>(variant_test_visit_dispatcher{}, variant_const);
|
||||
CHECK_EQUAL(10, type);
|
||||
|
||||
variant_test_visit_dispatcher visitor;
|
||||
type = etl::visit<int16_t>(visitor, variant_const);
|
||||
CHECK_EQUAL(50, type);
|
||||
|
||||
variant = int16_t{};
|
||||
type = etl::visit<int16_t>(variant_test_visit_dispatcher{}, variant);
|
||||
CHECK_EQUAL(3, type);
|
||||
|
||||
type = etl::visit<int16_t>(variant_test_visit_dispatcher{}, variant_const);
|
||||
CHECK_EQUAL(30, type);
|
||||
|
||||
type = etl::visit<int16_t>(visitor, variant_const);
|
||||
CHECK_EQUAL(70, type);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -1167,5 +1167,163 @@ namespace
|
||||
pcd = etl::get_if<1U>(&crv);
|
||||
CHECK(pcd == nullptr);
|
||||
}
|
||||
|
||||
|
||||
struct variant_test_visit_dispatcher
|
||||
{
|
||||
// const overloads
|
||||
int8_t operator()(int8_t&) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int8_t operator()(int8_t const&) const
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
int8_t operator()(uint8_t&) const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
int8_t operator()(uint8_t const&) const
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
int8_t operator()(int16_t&) const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
int8_t operator()(int16_t const&) const
|
||||
{
|
||||
return 30;
|
||||
}
|
||||
|
||||
// non-const overloads
|
||||
int8_t operator()(int8_t&)
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
int8_t operator()(int8_t const&)
|
||||
{
|
||||
return 50;
|
||||
}
|
||||
int8_t operator()(uint8_t&)
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
int8_t operator()(uint8_t const&)
|
||||
{
|
||||
return 60;
|
||||
}
|
||||
int8_t operator()(int16_t&)
|
||||
{
|
||||
return 7;
|
||||
}
|
||||
int8_t operator()(int16_t const&)
|
||||
{
|
||||
return 70;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int8_t operator()(T const&) const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
//*************************************************************************
|
||||
TEST(test_variant_visit)
|
||||
{
|
||||
etl::variant<int8_t, uint8_t, int16_t> variant;
|
||||
variant = int8_t{};
|
||||
variant_test_visit_dispatcher visitor;
|
||||
auto const& visitor_const = visitor;
|
||||
int16_t type = etl::visit(visitor_const, variant);
|
||||
CHECK_EQUAL(1, type);
|
||||
auto const& variant_const = variant;
|
||||
type = etl::visit(visitor_const, variant_const);
|
||||
CHECK_EQUAL(10, type);
|
||||
|
||||
type = etl::visit(visitor, variant_const);
|
||||
CHECK_EQUAL(50, type);
|
||||
|
||||
variant = int16_t{};
|
||||
type = etl::visit(visitor_const, variant);
|
||||
CHECK_EQUAL(3, type);
|
||||
|
||||
type = etl::visit(visitor_const, variant_const);
|
||||
CHECK_EQUAL(30, type);
|
||||
|
||||
type = etl::visit(visitor, variant_const);
|
||||
CHECK_EQUAL(70, type);
|
||||
}
|
||||
|
||||
struct test_variant_multiple_visit_helper
|
||||
{
|
||||
template <typename T1, typename T2>
|
||||
int16_t operator()(T1 v1, T2 v2) const
|
||||
{
|
||||
int16_t res{};
|
||||
if (std::is_same<T1, int8_t>::value)
|
||||
res = 1;
|
||||
else if (std::is_same<T1, uint8_t>::value)
|
||||
res = 2;
|
||||
if (std::is_same<T2, int8_t>::value)
|
||||
res += 10;
|
||||
else if (std::is_same<T2, uint16_t>::value)
|
||||
res += 20;
|
||||
else if (std::is_same<T2, uint8_t>::value)
|
||||
res += 30;
|
||||
return res - static_cast<int16_t>(v1) * static_cast<int16_t>(v2);
|
||||
}
|
||||
};
|
||||
//*************************************************************************
|
||||
TEST(test_variant_multiple_visit)
|
||||
{
|
||||
etl::variant<int8_t, uint8_t> variant1;
|
||||
etl::variant<int8_t, uint16_t, uint8_t> variant2;
|
||||
variant1 = int8_t{3};
|
||||
variant2 = int8_t{1};
|
||||
auto res = etl::visit<int16_t>(test_variant_multiple_visit_helper{}, variant1, variant2);
|
||||
CHECK_EQUAL(11 - 3, res);
|
||||
variant2 = uint16_t{2};
|
||||
res = etl::visit<int16_t>(test_variant_multiple_visit_helper{}, variant1, variant2);
|
||||
CHECK_EQUAL(21 - 3 * 2, res);
|
||||
variant1 = uint8_t{};
|
||||
variant2 = uint8_t{};
|
||||
res = etl::visit<int16_t>(test_variant_multiple_visit_helper{}, variant1, variant2);
|
||||
CHECK_EQUAL(32, res);
|
||||
}
|
||||
//*************************************************************************
|
||||
TEST(test_variant_multiple_visit_auto_return)
|
||||
{
|
||||
etl::variant<int8_t, uint8_t> variant1;
|
||||
etl::variant<int8_t, uint16_t, uint8_t> variant2;
|
||||
variant1 = int8_t{3};
|
||||
variant2 = int8_t{1};
|
||||
auto const f = [](auto v1, auto v2)
|
||||
{
|
||||
return v1 * v2;
|
||||
};
|
||||
auto res = etl::visit(f, variant1, variant2);
|
||||
CHECK_EQUAL(3, res);
|
||||
variant2 = uint16_t{2};
|
||||
res = etl::visit(f, variant1, variant2);
|
||||
CHECK_EQUAL(3 * 2, res);
|
||||
}
|
||||
//*************************************************************************
|
||||
TEST(test_variant_visit_void)
|
||||
{
|
||||
etl::variant<int8_t, uint8_t> variant1;
|
||||
|
||||
bool variant_was_signed{};
|
||||
auto const f = [&variant_was_signed](auto v)
|
||||
{
|
||||
variant_was_signed = etl::is_signed<etl::remove_reference_t<decltype(v)>>::value;
|
||||
};
|
||||
etl::visit(f, variant1);
|
||||
CHECK_EQUAL(true, variant_was_signed);
|
||||
variant1 = uint8_t{};
|
||||
etl::visit<void>(f, variant1);
|
||||
CHECK_EQUAL(false, variant_was_signed);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user