C++98/03 std::is_constructible implementation

后端 未结 2 1925
南旧
南旧 2020-12-19 02:42

The base components of my hobby library has to work with C++98 and C++11 compilers. To learn and to enjoy myself I created the C++98 implementations of several type support

相关标签:
2条回答
  • 2020-12-19 02:55

    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 from 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<class T>
    struct type_identity {
        // Used to work around Visual C++ 2008's spurious error: "a function-style conversion to a built-in type can only take one argument"
        typedef T type;
    };
    
    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(typename type_identity<U>::type(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 from 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 from 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(typename type_identity<U>::type(
                    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 the 2 parameters version for 3, 4, 5, ... parameters further more.

    Live Demo


    This works with g++ 4.4.7

    It doesn't work with g++ 4.3.6

    0 讨论(0)
  • 2020-12-19 03:15

    I think Danh's idea was great! With a minor modification we can eliminate the operator new. (I have a C++98 enable_if and remove_reference implementation). The mentioned int*, void* case works with this implementation too. No operator new required. Only the old g++ support remains...

    /********** std::remove_cv replacement **********/
    template< typename T >
    struct remove_const
    {
        typedef T type;
    };
    
    template< typename T >
    struct remove_const< const T >
    {
        typedef T type;
    };
    
    
    template< typename T >
    struct remove_volatile
    {
        typedef T type;
    };
    
    template< typename T >
    struct remove_volatile< volatile T >
    {
        typedef T type;
    };
    
    
    template< typename T >
    struct remove_cv
    {
        typedef typename remove_volatile< typename remove_const< T >::type >::type type;
    };
    
    
    /********** std::is_pointer replacement *********/
    template< typename T >
    struct is_pointer_helper
    {
        static const bool value = false;
    };
    
    template< typename T >
    struct is_pointer_helper< T* >
    {
        static const bool value = true;
    };
    
    template< typename T >
    struct is_pointer
    {
        static const bool value = is_pointer_helper< typename remove_cv< T >::type >::value;
    };
    
    
    /********** std::enable_if replacement **********/
    template< bool CONDITION, typename TYPE = void >
    struct enable_if
    {
    };
    
    template< typename TYPE >
    struct enable_if< true, TYPE >
    {
        typedef TYPE type;
    };
    
    
    /****** std::remove_reference replacement *******/
    template< typename T >
    struct remove_reference
    {
        typedef T type;
    };
    
    template< typename T >
    struct remove_reference< T& >
    {
        typedef T type;
    };
    
    
    /******* std::is_constructible replacement ******/
    template< typename T, typename AT_1 = void, typename AT_2 = void, typename AT_3 = void, typename AT_4 = void >
    class is_constructible_impl
    {
    private:
        template< typename C_T, typename C_AT_1, typename C_AT_2, typename C_AT_3, typename C_AT_4 >
        static bool test(
            typename c_std::enable_if<
                sizeof( C_T ) ==
                sizeof( C_T(
                    static_cast< C_AT_1 >( *static_cast< typename c_std::remove_reference< C_AT_1 >::type* >( NULL ) ),
                    static_cast< C_AT_2 >( *static_cast< typename c_std::remove_reference< C_AT_2 >::type* >( NULL ) ),
                    static_cast< C_AT_3 >( *static_cast< typename c_std::remove_reference< C_AT_3 >::type* >( NULL ) ),
                    static_cast< C_AT_4 >( *static_cast< typename c_std::remove_reference< C_AT_4 >::type* >( NULL ) )
                ) )
            >::type*
        );
    
        template< typename, typename, typename, typename, typename >
        static int test( ... );
    
    public:
        static const bool value = ( sizeof( test< T, AT_1, AT_2, AT_3, AT_4 >( NULL ) ) == sizeof( bool ) );
    };
    
    template< typename T, typename AT_1, typename AT_2, typename AT_3 >
    class is_constructible_impl< T, AT_1, AT_2, AT_3, void >
    {
    private:
        template< typename C_T, typename C_AT_1, typename C_AT_2, typename C_AT_3 >
        static bool test(
            typename c_std::enable_if<
                sizeof( C_T ) ==
                sizeof( C_T(
                    static_cast< C_AT_1 >( *static_cast< typename c_std::remove_reference< C_AT_1 >::type* >( NULL ) ),
                    static_cast< C_AT_2 >( *static_cast< typename c_std::remove_reference< C_AT_2 >::type* >( NULL ) ),
                    static_cast< C_AT_3 >( *static_cast< typename c_std::remove_reference< C_AT_3 >::type* >( NULL ) )
                ) )
            >::type*
        );
    
        template< typename, typename, typename, typename >
        static int test( ... );
    
    public:
        static const bool value = ( sizeof( test< T, AT_1, AT_2, AT_3 >( NULL ) ) == sizeof( bool ) );
    };
    
    template< typename T, typename AT_1, typename AT_2 >
    class is_constructible_impl< T, AT_1, AT_2, void, void >
    {
    private:
    
        template< typename C_T, typename C_AT_1, typename C_AT_2 >
        static bool test(
            typename c_std::enable_if<
                sizeof( C_T ) ==
                sizeof( C_T(
                    static_cast< C_AT_1 >( *static_cast< typename c_std::remove_reference< C_AT_1 >::type* >( NULL ) ),
                    static_cast< C_AT_2 >( *static_cast< typename c_std::remove_reference< C_AT_2 >::type* >( NULL ) )
                ) )
            >::type*
        );
    
        template< typename, typename, typename >
        static int test( ... );
    
    public:
        static const bool value = ( sizeof( test< T, AT_1, AT_2 >( NULL ) ) == sizeof( bool ) );
    };
    
    template< typename T, typename AT_1 >
    class is_constructible_impl< T, AT_1, void, void, void >
    {
    private:
        template< typename C_T, typename C_AT_1 >
        static bool test(
            typename c_std::enable_if<
                sizeof( C_T ) ==
                sizeof( C_T(
                    static_cast< C_AT_1 >( *static_cast< typename c_std::remove_reference< C_AT_1 >::type* >( NULL ) )
                ) )
            >::type*
        );
    
        template< typename, typename >
        static int test( ... );
    
    public:
        static const bool value = ( sizeof( test< T, AT_1 >( NULL ) ) == sizeof( bool ) );
    };
    
    template< typename T >
    class is_constructible_impl< T, void, void, void, void >
    {
    private:
        template< typename C_T >
        static C_T testFun( C_T );
    
        template< typename C_T >
        static bool test( typename c_std::enable_if< sizeof( C_T ) == sizeof( testFun( C_T() ) ) >::type* );
    
        template< typename >
        static int test( ... );
    
    public:
        static const bool value = ( sizeof( test< T >( NULL ) ) == sizeof( bool ) );
    };
    
    template< typename T, typename AT_1 = void, typename AT_2 = void, typename AT_3 = void, typename AT_4 = void >
    class is_constructible_impl_ptr
    {
    public:
        static const bool value = false;
    };
    
    template< typename T, typename AT_1 >
    class is_constructible_impl_ptr< T, AT_1, typename enable_if< is_pointer< typename remove_reference< T >::type >::value, void >::type, void, void >
    {
    private:
        template< typename C_T >
        static bool test( C_T );
    
        template< typename >
        static int test( ... );
    
    public:
        static const bool value = ( sizeof( test< T >( static_cast< AT_1 >( NULL ) ) ) == sizeof( bool ) );
    };
    
    template< typename T >
    class is_constructible_impl_ptr< T, void, void, void, void >
    {
    public:
        static const bool value = true;
    };
    
    template< typename T, typename AT_1 = void, typename AT_2 = void, typename AT_3 = void, typename AT_4 = void >
    class is_constructible
    {
    public:
        static const bool value = (
            is_pointer< typename remove_reference< T >::type >::value ?
                is_constructible_impl_ptr< T, AT_1, AT_2, AT_3, AT_4 >::value :
                is_constructible_impl< T, AT_1, AT_2, AT_3, AT_4 >::value
        );
    };
    
    0 讨论(0)
提交回复
热议问题