// (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; };
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