# 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