#include
#include
#include
#include
#include
#include
#include
#include
#include
#include"functiona_traits.h"
namespace ts
{
template<size_t I, typename...Types>
struct type_list
{
using type = std::tuple_element_t<I, std::tuple<Types...>>;
};
template<size_t I, typename...Types>
using type_list_t = typename type_list<I, Types...>::type;
template<typename T, typename...Args>
struct Integermax :std::integral_constant<int, (sizeof(T) > Integermax<Args...>::value ? sizeof(T) : Integermax<Args...>::value) >{ };
template<typename T>
struct Integermax<T> :std::integral_constant<int, sizeof(T) > {};
template<typename T,typename... Args>
struct MaxAlign :std::integral_constant<int, (alignof(T) > MaxAlign<Args...>::value ? alignof(T) : MaxAlign<Args...>::value) > {};
template<typename T>
struct MaxAlign<T> :std::integral_constant<int, alignof(T) > {};
template<typename T, typename ...List>
struct contains :std::true_type {};
template<typename T, typename head, typename ...rest>
struct contains<T, head, rest...> :std::conditional_t<std::is_same_v<T, head>, std::true_type, typename contains<T, rest...>::type> {};
template<typename T>
struct contains<T> :std::false_type {};
template <class... Types>
struct Variant
{
static const int datasize = Integermax<Types...>::value;
static const int alignsize = MaxAlign<Types...>::value;
using data_t= std::aligned_storage_t<datasize, alignsize>;
template<typename T,typename...Args>
struct helper
{
template<typename U>
static void init(U&& arg, data_t* data, std::type_index* ptid)
{
if constexpr (std::is_constructible_v<T, U>)
{
*ptid = std::type_index(typeid(T));
new(data)T(arg);
}
else
helper<Args...>::init(std::forward<U>(arg), data, ptid);
}
static void copy(std::type_index id,const data_t* other, data_t* dest)
{
if (id == std::type_index(typeid(T)))
new(dest) T(*reinterpret_cast<const T*>(other));
else
helper<Args...>::copy(id, other, dest);
}
static void move(std::type_index id, data_t* other, data_t* dest)
{
if (id == std::type_index(typeid(T)))
new(dest)T(std::move(*reinterpret_cast<T*>(other)));
else
helper<Args...>::move(id, other, dest);
}
static void destroy(std::type_index id, data_t* data)
{
if (id == std::type_index(typeid(T)))
reinterpret_cast<T*>(data)->~T();
else
helper<Args...>::destroy(id, data);
}
static int index(std::type_index id,size_t index)
{
if (id == std::type_index(typeid(T)))
return index;
else
return helper<Args...>::index(id, index+1);
}
};
template<typename T>
struct helper<T>
{
template<typename U>
static void init(U&& arg, data_t* data, std::type_index* ptid)
{
if constexpr (std::is_constructible_v<T, U>)
{
*ptid = std::type_index(typeid(T));
new(data)T(arg);
}
else
throw std::exception{};
}
static void copy(std::type_index id, const data_t* other, data_t* dest)
{
if (id == std::type_index(typeid(T)))
new(dest)T(*reinterpret_cast<const T*>(other));
else
throw std::exception{};
}
static void move(std::type_index id, data_t* other, data_t* dest)
{
if (id == std::type_index(typeid(T)))
new(dest)T(std::move(*reinterpret_cast<T*>(other)));
else
throw std::exception{};
}
static void destroy(std::type_index id, data_t* data)
{
if (id == std::type_index(typeid(T)))
reinterpret_cast<T*>(data)->~T();
else
throw std::exception{};
}
static int index(std::type_index id, size_t index)
{
if (id == std::type_index(typeid(T)))
return index;
else
throw std::exception{};
}
};
constexpr Variant(const Variant& other):m_tpIndex(other.m_tpIndex)
{
helper<Types...>::copy(other.m_tpIndex, &other.m_data, &m_data);
}
constexpr Variant(Variant&& other):m_tpIndex(other.m_tpIndex)
{
helper<Types...>::move(other.m_tpIndex, &other.m_data, &m_data);
}
template< typename U,std::enable_if_t<std::negation_v<std::is_same<Variant,std::_Remove_cvref_t<U>>>,int> =0 >
constexpr Variant(U&& t):m_tpIndex(std::type_index(typeid(void)))
{
helper<Types...>::init(std::forward<U>(t), &m_data, &m_tpIndex);
}
constexpr Variant& operator=(const Variant& other)
{
if (this != &other)
{
helper<Types...>::destroy(m_tpIndex, &m_data);
helper<Types...>::copy(other.m_tpIndex, &other.m_data, &m_data);
m_tpIndex = other.m_tpIndex;
}
return *this;
}
constexpr Variant& operator=(Variant&& other)
{
if (this != &other)
{
helper<Types...>::destroy(m_tpIndex, &m_data);
helper<Types...>::move(other.m_tpIndex, &other.m_data, &m_data);
m_tpIndex = other.m_tpIndex;
}
return *this;
}
template< typename U, std::enable_if_t<std::negation_v<std::is_same<Variant, std::_Remove_cvref_t<U>>>, int> = 0 >
constexpr Variant& operator=(U&& t)
{
helper<Types...>::destroy(m_tpIndex, &m_data);
helper<Types...>::init(std::forward<U>(t), &m_data, &m_tpIndex);
return *this;
}
//是否是当前类型状态
template<typename U>
constexpr bool is()
{
if(m_tpIndex == std::type_index(typeid(U)))
return true;
return false;
}
//获取类型状态的值,如果是U当前类型状态
template<typename U>
constexpr decltype(auto) get()
{
using type = std::decay_t<U>;
if (!is<type>())
{
std::cout << typeid(type).name() << "Not define!" << std::endl;
throw std::bad_cast();
}
return reinterpret_cast<type&>(m_data);
}
//根据模板参数列表索引取当前类型状态
template<size_t I>
constexpr decltype(auto) get()
{
using type = type_list_t<I, Types...>;
return get<type>();
}
//获取当前类型状态对应的模板参数表索引
constexpr size_t index()
{
return helper<Types...>::index(m_tpIndex, 0);
}
//U是否是模板参数表的类型状态
template<typename U>
bool has_type()
{
return contains<U, Types...>::value;
}
template<typename U>
int getindexof()
{
if (has_type<U>())
{
using type = std::decay_t<U>;
auto tid = std::type_index(typeid(type));
return helper<Types...>::index(tid, 0);
}
return -1;
}
//此访问者接口不同于C++标准std::visit;只能观察当前Variant本身,观察者符合要求才会调用到,否则不调用
template<typename F>
void visit(F&& f)
{
using T = std::decay_t<typename function_traits<std::decay_t<F>>::template ArgN_t<0>>;
if (is<T>())
f(get<T>());
}
template<typename F,typename...Rest>
void visit(F&& f, Rest&&...rest)
{
using T = std::decay_t<typename function_traits<std::decay_t<F>>::template ArgN_t<0>>;
if (is<T>())
visit(std::forward<F>(f));
else
visit(std::forward<Rest>(rest)...);
}
std::type_index m_tpIndex;
data_t m_data;
};
template< std::size_t I, typename... Types >
constexpr decltype(auto) Get(Variant<Types...>& v)
{
return v.get<I>();
}
void Print1(const std::string& s)
{
std::cout << s << std::endl;
}
void Print(int s)
{
std::cout << s << std::endl;
}
void test()
{
Variant<int, std::string, char*> v("123");
std::cout << v.getindexof<char*>() << std::endl;
std::cout << v.has_type<int>() << std::endl;
std::cout << v.get<std::string>() << std::endl;
// std::cout << v.get() << std::endl;
Variant<int, std::string, char*> v1(v);
std::cout << v1.getindexof<char*>() << std::endl;
std::cout << v1.has_type<int>() << std::endl;
std::cout << v1.get<std::string>() << std::endl;
// std::cout << v1.get() << std::endl;
v1 = 888;
std::cout << v1.getindexof<char*>() << std::endl;
std::cout << v1.has_type<int>() << std::endl;
std::cout << v1.get<int>() << std::endl;
v1 = v;
std::cout << v1.getindexof<char*>() << std::endl;
std::cout << v1.has_type<int>() << std::endl;
std::cout << v1.get<std::string>() << std::endl;
std::cout << Get<1>(v1) << std::endl;
v1.visit(Print, Print1);
// std::cout << v1.get<0>() << std::endl;
}
}
int main() {
ts::test();
return 0;
}
function_traits