#include <iostream>
typedef std::size_t SizeType;
template<typename T>
struct Identity
{
typedef T Type;
};
typedef Identity<char(&)[1]>::Type NoType;
typedef Identity<char(&)[2]>::Type YesType;
template<typename T, T Val>
struct IntegralConstant : public Identity<IntegralConstant<T, Val> >
{
typedef T ValueType;
#ifdef Lib_Cpp11
static constexpr ValueType Value = Val;
constexpr operator ValueType() const
{
return this->Value;
}
#else // Lib_Cpp11
static const ValueType Value = Val;
operator ValueType() const
{
return this->Value;
}
#endif // Lib_Cpp11
};
template<SizeType Val>
struct SizeToType : public IntegralConstant<SizeType, Val>
{
};
template<bool Val>
struct BoolToType : public IntegralConstant<bool, Val>
{
};
template<typename T>
T& DeclVal();
namespace Detail
{
template<typename From, typename To>
class IsExplicitConvertible
{
template<typename FromT, typename ToT>
static NoType Check(...);
template<typename FromT, typename ToT>
static YesType Check(SizeToType<sizeof(static_cast<ToT>(DeclVal<FromT>()))>*);
public:
static const bool Value = sizeof(Check<From, To>(0)) == sizeof(YesType);
};
template<typename T>
class IsDefaultConstructible
{
template<typename U>
static NoType Check(...);
template<typename U>
static YesType Check(SizeToType<sizeof(U())>*);
public:
static const bool Value = sizeof(Check<T>(0)) == sizeof(YesType);
};
}
template<typename From, typename To>
struct IsExplicitConvertible : public BoolToType<Detail::IsExplicitConvertible<From, To>::Value>
{
};
template<typename T>
struct IsDefaultConstructible : public BoolToType<Detail::IsDefaultConstructible<T>::Value>
{
};
struct Foo1
{
explicit Foo1(int);
operator char();
};
class Foo2
{
Foo2();
};
struct Foo3
{
};
int main()
{
std::cout << IsExplicitConvertible<int, float>::Value << '\n'; // Sollte 1 sein
std::cout << IsExplicitConvertible<int, Foo1>::Value << '\n'; // Sollte 1 sein
std::cout << IsExplicitConvertible<float, Foo1>::Value << '\n'; // Sollte 1 sein
std::cout << IsExplicitConvertible<Foo1, char>::Value << '\n'; // Sollte 1 sein
std::cout << IsExplicitConvertible<Foo1, double>::Value << '\n'; // Sollte 1 sein
std::cout << IsExplicitConvertible<bool, Foo2>::Value << '\n'; // Sollte 0 sein
std::cout << IsExplicitConvertible<int, void*>::Value << '\n'; // Sollte 0 sein
std::cout << '\n';
std::cout << IsDefaultConstructible<int>::Value << '\n'; // Sollte 1 sein
std::cout << IsDefaultConstructible<Foo1>::Value << '\n'; // Sollte 0 sein
std::cout << IsDefaultConstructible<Foo2>::Value << '\n'; // Sollte 0 sein
std::cout << IsDefaultConstructible<Foo3>::Value << '\n'; // Sollte 1 sein
}