c++ - C++98/03 std::is_constructible implementation -
the base components of hobby library has work c++98 , c++11 compilers. learn , enjoy myself created c++98 implementations of several type support functionality (like enable_if
, conditional
, is_same
, is_integral
etc. ...) in order use them when there no c++11 support.
however while implementing is_constructible
got stuck. there kind of template magic (some kind of sfinae) can implement without c++11 support (declval
)?
of course there no variadic template support in c++03, specialise implementation till depth. main question if there technique can decide whether t constructible given types or not.
it's possible:
#include <iostream> template<typename t, t val> struct integral_constant { typedef integral_constant type; typedef t value_type; enum { value = val }; }; typedef integral_constant<bool, true> true_type; typedef integral_constant<bool, false> false_type; template<typename t> struct remove_ref { typedef t type; }; template<typename t> struct remove_ref<t&> { typedef t type; }; // is_base_of https://stackoverflow.com/questions/2910979/how-does-is-base-of-work namespace aux { typedef char yes[1]; typedef char no[2]; template <typename b, typename d> struct host { operator b*() const; operator d*(); }; } template <typename b, typename d> struct is_base_of { template <typename t> static aux::yes& check(d*, t); static aux::no& check(b*, int); static const bool value = sizeof(check(aux::host<b,d>(), int())) == sizeof(aux::yes); }; template<typename t> struct remove_cv { typedef t type; }; template<typename t> struct remove_cv<const t> { typedef t type; }; template<typename t> struct remove_cv<volatile t> { typedef t type; }; template<typename t> struct remove_cv<const volatile t> { typedef t type; }; template<typename t> struct is_void : integral_constant<bool, false> {}; template<> struct is_void<void> : integral_constant<bool, true> {}; template <bool, typename t, typename> struct conditional { typedef t type; }; template <typename t, typename u> struct conditional<false, t, u> { typedef u type; }; namespace aux { template<typename t, typename u> struct is_more_const : integral_constant<bool, false> {}; template<typename t, typename u> struct is_more_const<const t, u> : integral_constant<bool, true> {}; template<typename t, typename u> struct is_more_const<const t, const u> : integral_constant<bool, false> {}; template<typename t, typename u> struct is_more_volatile : integral_constant<bool, false> {}; template<typename t, typename u> struct is_more_volatile<volatile t, u> : integral_constant<bool, true> {}; template<typename t, typename u> struct is_more_volatile<volatile t, volatile u> : integral_constant<bool, false> {}; template<typename t, typename u> struct is_more_cv : integral_constant<bool, is_more_const<t,u>::value && is_more_volatile<t,u>::value> {}; template<typename t> struct is_default_constructible { template<typename u> static yes& test(int(*)[sizeof(new u)]); template<typename u> static no& test(...); enum { value = sizeof(test<t>(0)) == sizeof(yes) }; }; template<typename t, typename arg> struct is_constructible_1 { template<typename u, typename arg_> static yes& test(int(*)[sizeof(u(static_cast<arg_>(*((typename remove_ref<arg_>::type*)0))))]); template<typename u, typename arg_> static no& test(...); enum { value = sizeof(test<t, arg>(0)) == sizeof(yes) }; }; // base pointer construct derived pointer template<typename t, typename u> struct is_constructible_1<t*, u*> : conditional< is_void<typename remove_cv<t>::type>::value, integral_constant<bool, true>, typename conditional< is_void<typename remove_cv<u>::type>::value, integral_constant<bool, false>, typename conditional< is_more_cv<t, u>::value, integral_constant<bool, false>, is_base_of<t,u> >::type >::type >::type {}; // base pointer construct derived pointer template<typename t, typename u> struct is_constructible_1<t&, u&> : conditional< is_more_cv<t, u>::value, integral_constant<bool, false>, is_base_of<t,u> >::type {}; template<typename t, typename arg1, typename arg2> struct is_constructible_2 { template<typename u, typename arg1_, typename arg2_> static yes& test(int(*)[ sizeof(u( static_cast<arg1_>(*((typename remove_ref<arg1_>::type*)0)), static_cast<arg2_>(*((typename remove_ref<arg2_>::type*)0)) )) ]); template<typename u, typename arg1_, typename arg2_> static no& test(...); enum { value = sizeof(test<t, arg1, arg2>(0)) == sizeof(yes) }; }; } template<typename t, typename arg1 = void, typename arg2 = void> struct is_constructible : integral_constant<bool, aux::is_constructible_2<t, arg1, arg2>::value> { }; template<typename t, typename arg> struct is_constructible<t, arg> : integral_constant<bool, aux::is_constructible_1<t, arg>::value> { }; template<typename t> struct is_constructible<t> : integral_constant<bool, aux::is_default_constructible<t>::value> { }; struct foo {}; struct fuzz_explicit {}; struct fuzz_implicit {}; struct fuzz { explicit fuzz(fuzz_explicit); fuzz(fuzz_implicit); }; struct buzz_explicit {}; struct buzz_implicit {}; struct buzz { explicit buzz(buzz_explicit); buzz(buzz_implicit); }; struct bar { bar(int); bar(int, double&); bar(fuzz); explicit bar(buzz); }; struct base {}; struct derived : base {}; #define test(x) std::cout << #x << x << '\n' int main() { test((is_constructible<foo>::value)); test((is_constructible<bar>::value)); test((is_constructible<foo, int>::value)); test((is_constructible<bar, int>::value)); test((is_constructible<foo, const foo&>::value)); test((is_constructible<bar, bar>::value)); test((is_constructible<bar, int, double>::value)); test((is_constructible<bar, int, double&>::value)); test((is_constructible<bar, int, const double&>::value)); test((is_constructible<int*, void*>::value)); test((is_constructible<void*, int*>::value)); test((is_constructible<base&, derived&>::value)); test((is_constructible<derived*, base*>::value)); // via fuzz test((is_constructible<bar, fuzz_explicit>::value)); test((is_constructible<bar, fuzz_implicit>::value)); // via buzz test((is_constructible<bar, buzz_explicit>::value)); test((is_constructible<bar, buzz_implicit>::value)); // integer promotion test((is_constructible<bar, char>::value)); // integer conversion test((is_constructible<bar, unsigned long>::value)); }
you can expand 2 parameters version 3, 4, 5, ... parameters further more.
this works g++ 4.4.7
it doesn't work g++ 4.3.6
Comments
Post a Comment