Skip to content

Instantly share code, notes, and snippets.

@Giemsa
Last active August 29, 2015 14:15
Show Gist options
  • Save Giemsa/79c2fc7ab20044e8c6c6 to your computer and use it in GitHub Desktop.
Save Giemsa/79c2fc7ab20044e8c6c6 to your computer and use it in GitHub Desktop.
眠れなかったからC++11でvariant的なやつ書いた
#include <iostream>
template<size_t ...N>
struct Max;
template<size_t N>
struct Max<N>
{
static constexpr size_t value = N;
};
template<size_t N, size_t ...R>
class Max<N, R...>
{
private:
static constexpr size_t r = Max<R...>::value;
public:
static constexpr size_t value = (N > r) ? N : r;
};
template<int N, typename F, typename ...T>
struct GetIndex_
{
static constexpr int value = -1;
};
template<int N, typename F, typename T, typename ...L>
struct GetIndex_<N, F, T, L...>
{
static constexpr int value =
std::is_same<F, T>::value ?
N :
GetIndex_<N + 1, F, L...>::value;
};
template<typename N, typename ...L>
struct GetIndex
{
static constexpr int value = GetIndex_<0, N, L...>::value;
};
template<typename N, typename ...L>
struct Find
{
static constexpr bool value = GetIndex<N, L...>::value >= 0;
};
template<bool C, typename T, typename S>
struct Select
{
using type = S;
};
template<typename T, typename S>
struct Select<true, T, S>
{
using type = T;
};
struct Void;
template<size_t N, size_t M, typename ...L>
struct Get_
{
using type = Void;
};
template<size_t N, size_t M, typename T, typename ...L>
struct Get_<N, M, T, L...>
{
using type = typename Select<N == M, T, typename Get_<N, M + 1, L...>::type>::type;
};
template<size_t N, typename ...L>
struct Get
{
using type = typename Get_<N, 0, L...>::type;
};
template<typename ...T>
using Storage = typename std::aligned_storage<
Max<sizeof(T)...>::value,
Max<std::alignment_of<T>::value...>::value
>::type;
template<int N, typename ...L>
struct Destructor
{
template<typename S>
static void call(const int index, S &storage)
{
if(index == N)
{
using U = typename Get<N, L...>::type;
reinterpret_cast<U *>(&storage)->~U();
}
else
{
Destructor<N - 1, L...>::call(index, storage);
}
}
};
template<typename ...L>
struct Destructor<0, L...>
{
template<typename S>
static void call(const int index, S &storage)
{
if(index == 0)
{
using U = typename Get<0, L...>::type;
reinterpret_cast<U *>(&storage)->~U();
}
}
};
template<typename ...T>
class Data final
{
private:
int type_;
Storage<T...> storage_;
public:
Data()
: type_(-1)
{ }
template<
typename U,
typename R = typename std::remove_cv<
typename std::remove_reference<U>::type
>::type,
typename = typename std::enable_if<Find<R, T...>::value>::type
>
Data(U &&data)
: type_(GetIndex<R, T...>::value)
{
new(&storage_) R(std::forward<U>(data));
}
~Data()
{
Destructor<sizeof...(T) - 1, T...>::call(type_, storage_);
}
template<
typename U,
typename = typename std::enable_if<Find<U, T...>::value>::type
>
U &get()
{
if(type_ != GetIndex<U, T...>::value)
{
throw 0; // type chigauyo!
}
return *reinterpret_cast<U *>(&storage_);
}
template<
typename U,
typename = typename std::enable_if<Find<U, T...>::value>::type
>
const U &get() const
{
if(type_ != GetIndex<U, T...>::value)
{
throw 0; // type chigauyo!
}
return *reinterpret_cast<const U *>(&storage_);
}
};
struct Hoge
{
Hoge()
{
std::cout << "ctor\n";
}
Hoge(const Hoge &hoge)
{
std::cout << "copy ctor\n";
}
Hoge(Hoge &&hoge)
{
std::cout << "move ctor\n";
}
~Hoge()
{
std::cout << "dtor\n";
}
};
std::ostream &operator<<(std::ostream &s, const Hoge &h)
{
s << "hoge kita!";
return s;
}
int main()
{
using D = Data<std::string, double, int, Hoge>;
D d = Hoge();
std::cout << d.get<Hoge>() << std::endl;
// std::cout << d.get<int>() << std::endl; // error!
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment