[Home]CPPTM Answers - Exercise 2-1

BOOST WIKI | RecentChanges | Preferences | Page List | Links List

 // (by Ariel Badichi)
 #include <cstddef>

 #include <boost/static_assert.hpp>
 #include <boost/type_traits/is_same.hpp>

 template<typename T1, typename T2>
 void same()
 {
     const bool v = boost::is_same<T1, T2>::value;
     BOOST_STATIC_ASSERT(v);
 }

 template<bool cond, typename X, typename Y>
 struct select;

 template<typename X, typename Y>
 struct select<true, X, Y>
 {
     typedef X type;
 };

 template<typename X, typename Y>
 struct select<false, X, Y>
 {
     typedef Y type;
 };

 // primary template assumes fundamental type

 template<typename C, typename X, typename Y>
 struct replace_type
 {
     static const bool issame = boost::is_same<C, X>::value;
     typedef typename select<issame, Y, C>::type type;
 };

 template<typename C, typename X, typename Y>
 struct replace_type<C *, X *, Y>
 {
     typedef typename replace_type<C, X *, Y>::type *up;
     static const bool issame = boost::is_same<C, X>::value;
     typedef typename select<issame, Y, up>::type type;
 };

 template<typename C, typename X, typename Y>
 struct replace_type<C &, X &, Y>
 {
     typedef typename replace_type<C, X &, Y>::type & up;
     static const bool issame = boost::is_same<C, X>::value;
     typedef typename select<issame, Y, up>::type type;
 };

 template<typename C, typename X, typename Y, std::size_t N>
 struct replace_type<C[N], X[N], Y>
 {
     typedef typename replace_type<C, X[N], Y>::type up[N];
     static const bool issame = boost::is_same<C, X>::value;
     typedef typename select<issame, Y, up>::type type;
 };

 template<typename C, typename X, typename Y>
 struct replace_type<C *, X, Y>
 {
     typedef typename replace_type<C, X, Y>::type *type;
 };

 template<typename C, typename X, typename Y>
 struct replace_type<C &, X, Y>
 {
     typedef typename replace_type<C, X, Y>::type & type;
 };

 template<typename C, typename X, typename Y, std::size_t N>
 struct replace_type<C[N], X, Y>
 {
     typedef typename replace_type<C, X, Y>::type type[N];
 };

 template<typename C, typename X, typename Y>
 struct replace_type<C (*)(), X, Y>
 {
     typedef typename replace_type<C, X, Y>::type R;
     typedef R (*type)();
 };

 template<typename C, typename X, typename Y, typename A>
 struct replace_type<C (*)(A), X, Y>
 {
     typedef typename replace_type<C, X, Y>::type R;
     typedef typename replace_type<A, X, Y>::type B;
     typedef R (*type)(B);
 };

 int main()
 {
     same<int, replace_type<void, void, int>::type>();
     same<int *, replace_type<void *, void, int>::type>();
     same<int &, replace_type<char &, char, int>::type>();
     same<int **, replace_type<void **, void, int>::type>();
     same<int *&, replace_type<void *&, void, int>::type>();
     same<int[5], replace_type<char[5], char, int>::type>();
     same<long *[10], replace_type<const int *[10], const int, long>::type>();
     same<int, replace_type<char (*)(char), char, int>::R>();
     same<int, replace_type<char (*)(char), char, int>::B>();
     same<long& (*)(long &), replace_type<char& (*)(char &), char, long>::type>();
     same<long& (*)(long &), replace_type<char& (*)(char &), char&, long&>::type>();
     same<long& (*)(int &), replace_type<char & (*)(int &), char&, long&>::type>();
     same<long *, replace_type<int **, int *, long>::type>();
     same<long &, replace_type<int **&, int **, long>::type>();

     return 0;
 }

// Warning!! it doesn't work for this replacement (Added by Jesus Andres)

 same<long* (*)(int *), replace_type<char * (*)(int *), char*, long*>::type>();

// Warning!! The template "select" may confus the GNU/G++ compiler, use "select2" instead or "select_type" // i.e: (Added by Jesus Andres)

    template<bool S,typename X, typename Y>    struct select_type{typedef X type;};

    template<typename X, typename Y>    struct select_type<false,X,Y>{typedef Y type;};

// Here is my solution (by Andrzej Polanski)

    template <class C, class X, class Y>
    struct replace_type;

    template <class C, class X, class Y, bool same>
    struct replace_type_impl;

    template <class C, class X, class Y>
    struct replace_type_impl<C,X,Y,true>
    {
        typedef Y type;
    };

    template <class C, class X, class Y>
    struct replace_type_impl<C,X,Y,false>
    {
        typedef C type;
    };

    template <class C, class X, class Y>
    struct replace_type_impl<C*,X,Y,false>
    {
        typedef typename replace_type<C,X,Y>::type * type;
    };

    template <class C, class X, class Y>
    struct replace_type_impl<C const,X,Y,false>
    {
        typedef typename replace_type<C,X,Y>::type const type;
    };

    template <class C, class X, class Y>
    struct replace_type_impl<C &,X,Y,false>
    {
        typedef typename replace_type<C,X,Y>::type & type;
    };

    template <class C, class X, class Y>
    struct replace_type_impl<C[],X,Y,false>
    {
        typedef typename replace_type<C,X,Y>::type type [];
    };

    template <class C, class X, class Y, int N>
    struct replace_type_impl<C[N],X,Y,false>
    {
        typedef typename replace_type<C,X,Y>::type type [N];
    };

    template <class X, class Y, class A, class B>
    struct replace_type_impl<A(*)(B),X,Y,false>
    {
        typedef typename replace_type<A,X,Y>::type (*type)(typename replace_type<B,X,Y>::type);
    };

    template <class X, class Y, class A, class B, class C>
    struct replace_type_impl<A(*)(B,C),X,Y,false>
    {
        typedef typename replace_type<A,X,Y>::type (*type)(typename replace_type<B,X,Y>::type, typename replace_type<C,X,Y>::type);
    };

    template <class C, class X, class Y>
    struct replace_type
    {
        static const bool is_same = boost::is_same<C, X>::value;
        typedef typename replace_type_impl<C,X,Y,is_same>::type type;
    };


Andriy Tylychko: I prefer Andrzej Polanski solution, but it has several problems:

	template <class X, class Y, class R> struct replace_type_impl<R (*)(B),X,Y,false>

it handles only POINTER to function, but pointers are handled separatly by

	template <class C, class X, class Y> struct replace_type_impl<C*,X,Y,false>

so correct version can look like:

	template <typename R, typename P, typename X, typename Y>
	struct replace_type_impl<R (P), X, Y, false>
	{
		typedef typename replace_type<R, X, Y>::type return_type;
		typedef typename replace_type<P, X, Y>::type param_type;
		typedef return_type type(param_type);
	};

such approach automatically handles a reference to function too. The same correction should be applied to

	template <class X, class Y, class A, class B, class C> struct replace_type_impl<A(*)(B,C),X,Y,false>

also, functions w/o parameters aren't handled at all, so add:

	template <typename R, typename X, typename Y>
	struct replace_type_impl<R (), X, Y, false>
	{
		typedef typename replace_type<R, X, Y>::type return_type;
		typedef return_type type();
	};

Andriy Tylychko, telya at mail dot ru



BOOST WIKI | RecentChanges | Preferences | Page List | Links List
Edit text of this page | View other revisions
Last edited January 6, 2008 5:34 pm (diff)
Search:
Disclaimer: This site not officially maintained by Boost Developers