partial variant
parent
f0e9475dcc
commit
8f3cbcb2fd
|
@ -1,6 +1,6 @@
|
||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
include(cmake/color.cmake)
|
include(cmake/color.cmake)
|
||||||
set(BLT_VERSION 5.4.5)
|
set(BLT_VERSION 5.4.6)
|
||||||
|
|
||||||
set(BLT_TARGET BLT)
|
set(BLT_TARGET BLT)
|
||||||
|
|
||||||
|
@ -238,6 +238,7 @@ if (${BUILD_TESTS})
|
||||||
blt_add_test(blt_iterator tests/iterator_tests.cpp test)
|
blt_add_test(blt_iterator tests/iterator_tests.cpp test)
|
||||||
blt_add_test(blt_argparse tests/argparse_tests.cpp test)
|
blt_add_test(blt_argparse tests/argparse_tests.cpp test)
|
||||||
blt_add_test(blt_logging tests/logger_tests.cpp test)
|
blt_add_test(blt_logging tests/logger_tests.cpp test)
|
||||||
|
blt_add_test(blt_variant tests/variant_tests.cpp test)
|
||||||
|
|
||||||
message("Built tests")
|
message("Built tests")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
|
@ -21,10 +21,10 @@
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <blt/std/types.h>
|
#include <blt/std/types.h>
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
namespace blt
|
namespace blt
|
||||||
{
|
{
|
||||||
|
@ -45,19 +45,33 @@ namespace blt
|
||||||
template <typename T, typename... Ts>
|
template <typename T, typename... Ts>
|
||||||
struct filter_void<T, Ts...>
|
struct filter_void<T, Ts...>
|
||||||
{
|
{
|
||||||
using type = std::conditional_t<
|
using type = std::conditional_t<std::is_same_v<T, void>, typename filter_void<Ts...>::type, decltype(std::tuple_cat(
|
||||||
std::is_same_v<T, void>,
|
std::declval<std::tuple<T>>(), std::declval<typename filter_void<Ts...>::type>()))>;
|
||||||
typename filter_void<Ts...>::type,
|
|
||||||
decltype(std::tuple_cat(
|
|
||||||
std::declval<std::tuple<T>>(),
|
|
||||||
std::declval<typename filter_void<Ts...>::type>()
|
|
||||||
))
|
|
||||||
>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
using filter_void_t = typename filter_void<Ts...>::type;
|
using filter_void_t = typename filter_void<Ts...>::type;
|
||||||
|
|
||||||
|
template <typename Type, typename... Ts>
|
||||||
|
struct filter_invoke;
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
struct filter_invoke<Type>
|
||||||
|
{
|
||||||
|
using type = std::tuple<>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Type, typename T, typename... Ts>
|
||||||
|
struct filter_invoke<Type, T, Ts...>
|
||||||
|
{
|
||||||
|
using type = std::conditional_t<std::is_invocable_v<T, Type>, decltype(std::tuple_cat(
|
||||||
|
std::declval<std::tuple<T>>(), std::declval<typename filter_invoke<Ts...>::type>())),
|
||||||
|
typename filter_invoke<Ts...>::type>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
using filter_invoke_t = typename filter_invoke<Ts...>::type;
|
||||||
|
|
||||||
template <typename Type, typename Func>
|
template <typename Type, typename Func>
|
||||||
struct member_func_meta
|
struct member_func_meta
|
||||||
{
|
{
|
||||||
|
@ -66,16 +80,21 @@ namespace blt
|
||||||
using return_type = std::conditional_t<can_invoke::value, std::invoke_result_t<Func, Type>, void>;
|
using return_type = std::conditional_t<can_invoke::value, std::invoke_result_t<Func, Type>, void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename Func, size_t Index, bool HasValue>
|
template <typename T, typename Func, size_t Index>
|
||||||
struct passthrough_value
|
struct passthrough_value
|
||||||
{
|
{
|
||||||
using type = T;
|
using type = T;
|
||||||
using func = Func;
|
using func = Func;
|
||||||
constexpr static size_t index = Index;
|
constexpr static size_t index = Index;
|
||||||
|
|
||||||
|
bool has_value;
|
||||||
|
|
||||||
|
explicit passthrough_value(const bool has_value): has_value(has_value)
|
||||||
|
{}
|
||||||
|
|
||||||
explicit operator bool() const
|
explicit operator bool() const
|
||||||
{
|
{
|
||||||
return HasValue;
|
return has_value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -85,14 +104,13 @@ namespace blt
|
||||||
template <size_t... Indexes>
|
template <size_t... Indexes>
|
||||||
constexpr static auto find_func(std::index_sequence<Indexes...>)
|
constexpr static auto find_func(std::index_sequence<Indexes...>)
|
||||||
{
|
{
|
||||||
return (... || []()
|
return (... || []() {
|
||||||
{
|
|
||||||
using Meta = member_func_meta<Type, Funcs>;
|
using Meta = member_func_meta<Type, Funcs>;
|
||||||
if constexpr (Meta::can_invoke::value)
|
if constexpr (Meta::can_invoke::value)
|
||||||
{
|
{
|
||||||
return passthrough_value<typename Meta::return_type, Funcs, Indexes, true>{};
|
return passthrough_value<typename Meta::return_type, Funcs, Indexes>{true};
|
||||||
}
|
}
|
||||||
return passthrough_value<void, Funcs, Indexes, false>{};
|
return passthrough_value<typename Meta::return_type, Funcs, Indexes>{false};
|
||||||
}());
|
}());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,56 +121,51 @@ namespace blt
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename FuncTuple, typename ArgTuple>
|
template <typename FuncTuple, typename ArgTuple>
|
||||||
struct member_func_detail
|
struct member_func_detail;
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename... Funcs, typename... Args>
|
template <typename... Funcs, typename... Args>
|
||||||
struct member_func_detail<std::tuple<Funcs...>, std::tuple<Args...>>
|
struct member_func_detail<std::tuple<Funcs...>, std::tuple<Args...>>
|
||||||
{
|
{
|
||||||
using result_types = std::tuple<first_invoke_member_func<Args, Funcs...>...>;
|
using result_types = std::tuple<first_invoke_member_func<Args, Funcs...>...>;
|
||||||
using base_type = typename decltype(std::get<0>(std::declval<result_types>))::type;
|
using base_type = typename std::tuple_element_t<0, result_types>::return_type;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using get_type = typename T::type;
|
using get_type = typename T::return_type;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using is_base = std::is_same<typename T::type, base_type>;
|
using is_base = std::is_same<T, base_type>;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using is_base_or_void = std::disjunction<std::is_void<typename T::type>, is_base<typename T::type>>;
|
using is_base_or_void = std::disjunction<std::is_void<typename T::return_type>, is_base<typename T::return_type>>;
|
||||||
|
|
||||||
template <template<typename...> typename Functor, template<typename> typename PerType, size_t... Indexes>
|
template <template<typename...> typename Functor, template<typename> typename PerType, size_t... Indexes>
|
||||||
constexpr static auto for_each_type(std::index_sequence<Indexes...>)
|
constexpr static auto for_each_type(std::index_sequence<Indexes...>)
|
||||||
{
|
{
|
||||||
return std::declval<Functor<PerType<decltype(std::get<Indexes>(std::declval<result_types>()))>...>>;
|
return std::declval<Functor<PerType<std::tuple_element_t<Indexes, result_types>>...>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static bool all_has_void = for_each_type<std::conjunction_v, std::is_void>(std::index_sequence_for<Args...>());
|
constexpr static bool all_has_void = std::decay_t<std::invoke_result_t<decltype(for_each_type<std::conjunction, std::is_void>(
|
||||||
constexpr static bool all_has_ret = for_each_type<std::conjunction_v, is_base>(std::index_sequence_for<Args...>());
|
std::index_sequence_for<Args...>()))>>::value;
|
||||||
constexpr static bool all_has_ret_or_void = for_each_type<std::conjunction_v, is_base_or_void>(std::index_sequence_for<Args...>());
|
constexpr static bool all_has_ret = std::decay_t<std::invoke_result_t<decltype(for_each_type<std::conjunction, is_base>(
|
||||||
|
std::index_sequence_for<Args...>()))>>::value;
|
||||||
|
constexpr static bool all_has_ret_or_void = std::decay_t<std::invoke_result_t<decltype(for_each_type<std::conjunction, is_base_or_void>(
|
||||||
|
std::index_sequence_for<Args...>()))>>::value;
|
||||||
|
|
||||||
using non_void_types = typename decltype(for_each_type<filter_void_t, get_type>(std::index_sequence_for<Args...>()))::type;
|
using non_void_types = typename std::decay_t<std::invoke_result_t<decltype(for_each_type<filter_void, get_type>(
|
||||||
|
std::index_sequence_for<Args...>()))>>::type;
|
||||||
|
|
||||||
template <size_t... Indexes>
|
template <size_t... Indexes>
|
||||||
static constexpr auto make_variant(std::index_sequence<Indexes...>)
|
static constexpr auto make_variant(std::index_sequence<Indexes...>)
|
||||||
{
|
{
|
||||||
if constexpr (all_has_void)
|
using variant = variant_t<std::decay_t<std::tuple_element_t<Indexes, non_void_types>>...>;
|
||||||
return;
|
|
||||||
using variant = variant_t<decltype(std::get<Indexes>(std::declval<non_void_types>()))...>;
|
|
||||||
return std::declval<variant>();
|
return std::declval<variant>();
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr auto make_return_type()
|
using make_return_type = std::conditional_t<all_has_void, void, std::conditional_t<
|
||||||
{
|
all_has_ret, base_type, std::conditional_t<
|
||||||
if constexpr (all_has_void)
|
all_has_ret_or_void, std::optional<base_type>, std::conditional_t<
|
||||||
return;
|
std::tuple_size_v<non_void_types> == 0, void, decltype(make_variant(
|
||||||
if constexpr (all_has_ret)
|
std::make_index_sequence<std::tuple_size_v<non_void_types>>{}))>>>>;
|
||||||
return std::declval<base_type>();
|
|
||||||
if constexpr (all_has_ret_or_void)
|
|
||||||
return std::declval<std::optional<base_type>>();
|
|
||||||
return make_variant(std::make_index_sequence<std::tuple_size_v<non_void_types>>{});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,13 +181,13 @@ namespace blt
|
||||||
using TLambdas::operator()...;
|
using TLambdas::operator()...;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if __cplusplus < 202002L
|
#if __cplusplus < 202002L
|
||||||
|
|
||||||
// explicit deduction guide (not needed as of C++20)
|
// explicit deduction guide (not needed as of C++20)
|
||||||
template <typename... TLambdas>
|
template <typename... TLambdas>
|
||||||
lambda_visitor(TLambdas...) -> lambda_visitor<TLambdas...>;
|
lambda_visitor(TLambdas...) -> lambda_visitor<TLambdas...>;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename... Types>
|
template <typename... Types>
|
||||||
class variant_t
|
class variant_t
|
||||||
|
@ -184,51 +197,41 @@ namespace blt
|
||||||
size_t variant_size = sizeof...(Types);
|
size_t variant_size = sizeof...(Types);
|
||||||
|
|
||||||
constexpr variant_t(): m_variant()
|
constexpr variant_t(): m_variant()
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
constexpr variant_t(const variant_t& variant) noexcept(std::is_nothrow_copy_constructible_v<value_type>): m_variant(variant.m_variant)
|
constexpr variant_t(const variant_t& variant) noexcept(std::is_nothrow_copy_constructible_v<value_type>): m_variant(variant.m_variant)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
constexpr variant_t(variant_t&& variant) noexcept(std::is_nothrow_move_constructible_v<value_type>): m_variant(std::move(variant.m_variant))
|
constexpr variant_t(variant_t&& variant) noexcept(std::is_nothrow_move_constructible_v<value_type>): m_variant(std::move(variant.m_variant))
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
explicit constexpr variant_t(const value_type& variant) noexcept(std::is_nothrow_copy_constructible_v<value_type>): m_variant(variant)
|
explicit constexpr variant_t(const value_type& variant) noexcept(std::is_nothrow_copy_constructible_v<value_type>): m_variant(variant)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
explicit constexpr variant_t(value_type&& variant) noexcept(std::is_nothrow_move_constructible_v<value_type>): m_variant(std::move(variant))
|
explicit constexpr variant_t(value_type&& variant) noexcept(std::is_nothrow_move_constructible_v<value_type>): m_variant(std::move(variant))
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
explicit constexpr variant_t(Types&&... args) noexcept(std::is_nothrow_constructible_v<value_type, Types...>): m_variant(
|
explicit constexpr variant_t(Types&&... args) noexcept(std::is_nothrow_constructible_v<value_type, Types...>): m_variant(
|
||||||
std::forward<Types>(args)...)
|
std::forward<Types>(args)...)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename... C_Args>
|
template <typename T, typename... C_Args>
|
||||||
explicit constexpr variant_t(std::in_place_type_t<T>, C_Args&&... args): m_variant(std::in_place_type<T>, std::forward<C_Args>(args)...)
|
explicit constexpr variant_t(std::in_place_type_t<T>, C_Args&&... args): m_variant(std::in_place_type<T>, std::forward<C_Args>(args)...)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename U, typename... C_Args>
|
template <typename T, typename U, typename... C_Args>
|
||||||
constexpr explicit variant_t(std::in_place_type_t<T>, std::initializer_list<U> il, C_Args&&... args): m_variant(
|
constexpr explicit variant_t(std::in_place_type_t<T>, std::initializer_list<U> il, C_Args&&... args): m_variant(
|
||||||
std::in_place_type<T>, il, std::forward<C_Args>(args)...)
|
std::in_place_type<T>, il, std::forward<C_Args>(args)...)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t I, typename... C_Args>
|
template <size_t I, typename... C_Args>
|
||||||
explicit constexpr variant_t(std::in_place_index_t<I>, C_Args&&... args): m_variant(std::in_place_index<I>, std::forward<C_Args>(args)...)
|
explicit constexpr variant_t(std::in_place_index_t<I>, C_Args&&... args): m_variant(std::in_place_index<I>, std::forward<C_Args>(args)...)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
template <std::size_t I, typename U, typename... C_Args>
|
template <std::size_t I, typename U, typename... C_Args>
|
||||||
constexpr explicit variant_t(std::in_place_index_t<I>, std::initializer_list<U> il, C_Args&&... args): m_variant(
|
constexpr explicit variant_t(std::in_place_index_t<I>, std::initializer_list<U> il, C_Args&&... args): m_variant(
|
||||||
std::in_place_index<I>, il, std::forward<C_Args>(args)...)
|
std::in_place_index<I>, il, std::forward<C_Args>(args)...)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
T& emplace(Args&&... args)
|
T& emplace(Args&&... args)
|
||||||
|
@ -271,18 +274,14 @@ namespace blt
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Automatic visitor generation with empty default behavior
|
* Automatic visitor generation
|
||||||
* @param visitees user lambdas
|
* @param visitees user lambdas
|
||||||
*/
|
*/
|
||||||
template <typename... Visitee>
|
template <typename... Visitee>
|
||||||
constexpr auto visit(Visitee&&... visitees) -> decltype(detail::member_func_detail<std::tuple<Visitee...>, std::tuple<Types...>>::make_return_type())
|
constexpr auto visit(
|
||||||
|
Visitee&&... visitees) -> typename detail::member_func_detail<std::tuple<Visitee...>, std::tuple<Types...>>::make_return_type
|
||||||
{
|
{
|
||||||
return std::visit(lambda_visitor{
|
return std::visit(lambda_visitor{std::forward<Visitee>(visitees)...}, m_variant);
|
||||||
std::forward<Visitee>(visitees)...,
|
|
||||||
[](auto)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}, m_variant);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Default, typename... Visitee>
|
template <typename Default, typename... Visitee>
|
||||||
|
@ -290,46 +289,18 @@ namespace blt
|
||||||
{
|
{
|
||||||
return std::visit(lambda_visitor{
|
return std::visit(lambda_visitor{
|
||||||
std::forward<Visitee>(visitees)...,
|
std::forward<Visitee>(visitees)...,
|
||||||
[default_value=std::forward<Default>(default_value)](auto&& value)
|
[default_value=std::forward<Default>(default_value)](auto&& value) {
|
||||||
{
|
|
||||||
return std::forward<decltype(value)>(value);
|
return std::forward<decltype(value)>(value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... MemberFuncs>
|
|
||||||
constexpr auto call_member(const MemberFuncs... funcs)
|
|
||||||
{
|
|
||||||
static_assert(std::conjunction_v<std::is_member_function_pointer<std::decay_t<MemberFuncs>>...>,
|
|
||||||
"Must provide only pointers to member functions!");
|
|
||||||
using meta_t = detail::member_func_detail<std::tuple<MemberFuncs...>, std::tuple<Types...>>;
|
|
||||||
using result_t = decltype(meta_t::make_return_type());
|
|
||||||
return std::visit([=](auto&& value) -> result_t
|
|
||||||
{
|
|
||||||
using ValueType = std::decay_t<decltype(value)>;
|
|
||||||
|
|
||||||
if constexpr (std::disjunction_v<std::is_invocable<std::decay_t<decltype(funcs)>, ValueType>...>)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
return *(... || ([&](auto&& func) -> decltype(auto)
|
|
||||||
{
|
|
||||||
using FuncType = std::decay_t<decltype(func)>;
|
|
||||||
using ReturnType = std::invoke_result_t<FuncType, ValueType>;
|
|
||||||
if constexpr (std::is_invocable_v<FuncType, ValueType>)
|
|
||||||
{
|
|
||||||
return ((value).*(func))();
|
|
||||||
}
|
|
||||||
return std::declval<result_t>();
|
|
||||||
}(cast_member_ptr<std::decay_t<decltype(value)>>(std::forward<decltype(funcs)>(funcs)))));
|
|
||||||
}, m_variant);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename MemberFunc, typename... Args>
|
template <typename MemberFunc, typename... Args>
|
||||||
constexpr auto call_member_args(const MemberFunc func, Args&&... args)
|
constexpr auto call_member(const MemberFunc func,
|
||||||
{
|
Args&&... args) -> typename detail::member_func_detail<
|
||||||
return std::visit([=](auto&& value)
|
std::tuple<MemberFunc>, std::tuple<Types...>>::make_return_type
|
||||||
{
|
{
|
||||||
|
return std::visit([func,...args=std::forward<Args>(args)](auto&& value) {
|
||||||
return ((value).*(func))(std::forward<Args>(args)...);
|
return ((value).*(func))(std::forward<Args>(args)...);
|
||||||
}, m_variant);
|
}, m_variant);
|
||||||
}
|
}
|
||||||
|
@ -478,8 +449,7 @@ namespace blt
|
||||||
{
|
{
|
||||||
template <typename>
|
template <typename>
|
||||||
class variant_is_base_of
|
class variant_is_base_of
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template <typename... Types>
|
template <typename... Types>
|
||||||
class variant_is_base_of<variant_t<Types...>>
|
class variant_is_base_of<variant_t<Types...>>
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit d88c5e15079047777b418132ece5879e7c9aaa2b
|
Subproject commit 93201da2ba5a6aba0a6e57ada64973555629b3e3
|
|
@ -0,0 +1,135 @@
|
||||||
|
/*
|
||||||
|
* <Short Description>
|
||||||
|
* Copyright (C) 2025 Brett Terpstra
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <blt/std/variant.h>
|
||||||
|
#include <blt/logging/logging.h>
|
||||||
|
#include <blt/std/assert.h>
|
||||||
|
|
||||||
|
struct base_type
|
||||||
|
{
|
||||||
|
[[nodiscard]] virtual int simple() const = 0;
|
||||||
|
[[nodiscard]] virtual std::string to_string() const = 0;
|
||||||
|
|
||||||
|
virtual ~base_type() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mutate_type : base_type
|
||||||
|
{
|
||||||
|
virtual void mutate(int i) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct type1 final : base_type
|
||||||
|
{
|
||||||
|
[[nodiscard]] int simple() const override // NOLINT
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::string to_string() const override // NOLINT
|
||||||
|
{
|
||||||
|
return "Type1";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct type2 final : base_type
|
||||||
|
{
|
||||||
|
[[nodiscard]] int simple() const override // NOLINT
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::string to_string() const override // NOLINT
|
||||||
|
{
|
||||||
|
return "Type2";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct type3 final : base_type
|
||||||
|
{
|
||||||
|
[[nodiscard]] int simple() const override // NOLINT
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::string to_string() const override // NOLINT
|
||||||
|
{
|
||||||
|
return "Type3";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct storing_type1 final : mutate_type
|
||||||
|
{
|
||||||
|
explicit storing_type1(const int i): internal(i)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] int simple() const override // NOLINT
|
||||||
|
{
|
||||||
|
return internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutate(const int i) override
|
||||||
|
{
|
||||||
|
internal = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::string to_string() const override // NOLINT
|
||||||
|
{
|
||||||
|
return "Storing Type: {" + std::to_string(internal) + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
int internal;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct storing_type2 final : mutate_type
|
||||||
|
{
|
||||||
|
explicit storing_type2(const float i): internal(i * 2.2534f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] int simple() const override // NOLINT
|
||||||
|
{
|
||||||
|
return static_cast<int>(internal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutate(const int i) override
|
||||||
|
{
|
||||||
|
internal = static_cast<float>(i) * 2.2534f;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] std::string to_string() const override // NOLINT
|
||||||
|
{
|
||||||
|
return "Storing Type: {" + std::to_string(internal) + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
float internal;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
|
||||||
|
blt::variant_t<type1, type2, type3> v1{type1{}};
|
||||||
|
blt::variant_t<type1, type2, type3> v2{type2{}};
|
||||||
|
blt::variant_t<type1, type2, type3> v3{type3{}};
|
||||||
|
|
||||||
|
BLT_TRACE("Variants to_string():");
|
||||||
|
BLT_TRACE("V1: {}", v1.call_member(&base_type::to_string));
|
||||||
|
BLT_TRACE("V2: {}", v2.call_member(&base_type::to_string));
|
||||||
|
BLT_TRACE("V3: {}", v3.call_member(&base_type::to_string));
|
||||||
|
}
|
Loading…
Reference in New Issue