specialization of a template function in a template class?!?!?

  • Thread starter pookiebearbottom
  • Start date
P

pookiebearbottom

Just trying to learn some things about templates. Was wondering how
boost::tupple really works, but the headers were a bit confusing to me.
I know you get do something like the following, just want to know how
it works with the overloading of get<>().

boost::tupple<int,double> tup(1,2.0);

double d=tup.get<2>(); // equal 2.0

// simple set up,
template <class T1,class T2> class MyPair
{
public:
T1* m_t1;
T2* m_t2;
MyPair(T1* t1,T2* t2)
: m_t1(t1), m_t2(t2)
{}

// want to know how to do this
template <int J> T1* get() {return m_t1;}

// just wondering if I could do this
template <class J> J* get() {return 0;}
};

// can I specialize this way?
template <class T1,class T2> T1* MyPair<T1,T2>::get<1>() { return
m_t1;}
template <class T1,class T2> T2* MyPair<T1,T2>::get<2>() { return
m_t2;}

// specialized this way??!?!?
template <class T1,class T2> T1* MyPair<T1,T2>::get<T1>() { return
m_t1;}
template <class T1,class T2> T2* MyPair<T1,T2>::get<T2>() { return
m_t2;}

thanks
-sal
 
A

Alan Johnson

Just trying to learn some things about templates. Was wondering how
boost::tupple really works, but the headers were a bit confusing to me.
I know you get do something like the following, just want to know how
it works with the overloading of get<>().

boost::tupple<int,double> tup(1,2.0);

double d=tup.get<2>(); // equal 2.0

// simple set up,
template <class T1,class T2> class MyPair
{
public:
T1* m_t1;
T2* m_t2;
MyPair(T1* t1,T2* t2)
: m_t1(t1), m_t2(t2)
{}

// want to know how to do this
template <int J> T1* get() {return m_t1;}

// just wondering if I could do this
template <class J> J* get() {return 0;}
};

// can I specialize this way?
template <class T1,class T2> T1* MyPair<T1,T2>::get<1>() { return
m_t1;}
template <class T1,class T2> T2* MyPair<T1,T2>::get<2>() { return
m_t2;}

// specialized this way??!?!?
template <class T1,class T2> T1* MyPair<T1,T2>::get<T1>() { return
m_t1;}
template <class T1,class T2> T2* MyPair<T1,T2>::get<T2>() { return
m_t2;}

thanks
-sal

I realize the nature of your question prevents posting compilable code,
but you should at least try to reduce the errors to the part you are
asking about. In particular, you need to include
<boost/tuple/tuple.hpp>, you need to spell tuple correctly (not
tupple), and get uses a zero based index, so you should be using get<1>
instead of get<2>.

Now, to answer your question, you cannot specialize a template unless
all enclosing templates are totally specialized. Why is this? Beats
me. I see no good reason for the restriction, but the standard doesn't
allow it. One thing you may try (a quick glance at tuple's
implementation suggests boost does something like this) is to create a
non-member template function, and forward calls to you member function
to the non-member version. Then specialize the non-member version
however you like.

Getting the correct return type for your get function can be tricky.
The best solution is to create some sort of metafunction that produces
the correct type for you.

There is another set of problems to deal with. Particularly, that a
function cannot be partially specialized (and you would like to
specialize it based on the types T1 and T2, as well as the return
type). So, instead of using a non-member function, it may be necessary
to use a static member of a separate class.

All put together, it is going to look something like this (I've removed
your second set of specializations. Consider them an exercise for the
reader.):

// Metafunction to help us get the return type.
template <int N, class T1, class T2>
struct ReturnTraits ;

template <class T1, class T2>
struct ReturnTraits<0, T1, T2>
{
typedef T1 ReturnType ;
} ;

template <class T1, class T2>
struct ReturnTraits<1, T1, T2>
{
typedef T2 ReturnType ;
} ;

// Helper to which we delegate calls to get to get around
specialization rules.
template <int N, class ReturnType, class PairType> struct get_class ;

template <class ReturnType, class PairType>
struct get_class<0, ReturnType, PairType>
{
static ReturnType get(PairType & p)
{
p.m_t1 ;
}
} ;

template <class ReturnType, class PairType>
struct get_class<1, ReturnType, PairType>
{
static ReturnType get(PairType & p)
{
p.m_t2 ;
}
} ;

// simple set up,
template <class T1,class T2> class MyPair
{
public:
T1* m_t1;
T2* m_t2;
MyPair(T1* t1,T2* t2)
: m_t1(t1), m_t2(t2)
{}

// want to know how to do this
template <int J>
typename ReturnTraits<J, T1, T2>::ReturnType * get()
{
return get_class<J, typename ReturnTraits<J, T1,
T2>::ReturnType,
MyPair<T1, T2> >::get();
}
};
 
P

pookiebearbottom

Alan said:
(e-mail address removed) wrote:
....

Thanks for the long answer Alan. FYI, didn't post boost code because I
know how to use tupple, I wanted to know how the templates worked so I
could try something similar here.

Anyway, thanks again for the in-depth answer. Going to take me a while
to digest it.

-sal
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top