Explicit template instanciation, what is incorrect

L

Leon Pollak

I shall be thankful for the help with the following:

Class declaration:
template <int Index, int Prio, int Dir>
class cNHI_Task : public cChnlTask, cNHI_DTS {
....
virtual void Body();
}

I should like to have two different methods "Body" for Dir=0 and Dir=1. But
all my attempts like:

template <int Index, int Prio, int Dir>
void cNHI_Task<Index, Prio, 1>::Body() {}

or

template <int Index, int Prio>
void cNHI_Task<Index, Prio, 1>::Body() {}

or similar failed.

Studing the internet for hours dos not help...:(

Any comments, please?
 
A

Abhishek Padmanabh

I shall be thankful for the help with the following:

Class declaration:
template <int Index, int Prio, int Dir>
class cNHI_Task : public cChnlTask, cNHI_DTS {
...
virtual void Body();

}

I should like to have two different methods "Body" for Dir=0 and Dir=1.. But
all my attempts like:

template <int Index, int Prio, int Dir>
void cNHI_Task<Index, Prio, 1>::Body() {}

or

template <int Index, int Prio>
void cNHI_Task<Index, Prio, 1>::Body() {}

or similar failed.

Studing the internet for hours dos not help...:(

Any comments, please?

You cannot have 2 bodies for the same function of the same template.
You would need to specialize the class template for Dir = 1 and Dir =
2 individually, in order to achieve that.

I tried making the member function Body() as a template but even that
would not work as specializing a member template without specializing
the class template is not allowed. Moreover, virtual member function
templates are not allowed.

Here is how you would specialize your class cNHI_Task:

class cChnlTask{};
class cNHI_DTS{};

template <int Index, int Prio, int Dir>
class cNHI_Task : public cChnlTask, cNHI_DTS {
public:
virtual void Body()
{
std::cout << "Dir = " << Dir << std::endl;
}
};

template <int Index, int Prio>
class cNHI_Task <Index,Prio,1> : public cChnlTask, cNHI_DTS {
public:
virtual void Body()
{
std::cout << "Specialization : Dir = " << 1 << std::endl;
}
};

template <int Index, int Prio>
class cNHI_Task <Index,Prio,2> : public cChnlTask, cNHI_DTS {
public:
virtual void Body()
{
std::cout << "Specialization : Dir = " << 2 << std::endl;
}
};

int main()
{
cNHI_Task<0,0,1> obj_dir_1;
cNHI_Task<0,0,2> obj_dir_2;
cNHI_Task<0,0,3> obj_dir_3;
obj_dir_1.Body();
obj_dir_2.Body();
obj_dir_3.Body();
}
 
L

Leon Pollak

Thank you Abhishek.
Your answer is complete and clear. The only question I still have is: why in
the case of one parameter in the template everything works fine? I mean, I
can do explicit specification like
template<> .....
And in this case I do can have several bodies of the same function!

Thanks ahead
 
A

Abhishek Padmanabh

The only question I still have is: why in
the case of one parameter in the template everything works fine?

Sorry, but I did not understand what you ask here. What do you mean by
one parameter in template?
I mean, I
can do explicit specification like
template<> .....
And in this case I do can have several bodies of the same function!

If you do explicit specialization of your class, you can have any
number of bodies of that function but that will be equal to the number
of specializations you provide. That will also depends on what values
of Index and Prio do you specialize them for.
 
L

Leon Pollak

And just to clarify your decision:
The template class has many other methods. Your method involves the
necessity to duplicate everything in declaration, yes?

Thanks ahead.
 
C

Colin Caughie

Leon said:
Thank you Abhishek.
Your answer is complete and clear. The only question I still have is: why in
the case of one parameter in the template everything works fine? I mean, I
can do explicit specification like
template<> .....
And in this case I do can have several bodies of the same function!

What you're trying to do here is called partial specialization; i.e.
you're fixing one of the template parameters but leaving the rest
unspecified.

You can do this with class/struct templates but not with function
templates as you're trying to do here. When you specialize a function
template you have to fix all of the parameters, not just some of them.

You can generally get around this by making use of a helper class
template, e.g.

template <int Index, int Prio, int Dir>
struct my_helper;

template <int Index, int Prio>
struct my_helper< Index, Prio, 0 >
{
static void DoBody()
{
// Body for Dir=0
}
}

template <int Index, int Prio>
struct my_helper< Index, Prio, 1 >
{
static void DoBody()
{
// Body for Dir=1
}
}

template <int Index, int Prio, int Dir>
class cNHI_Task : public cChnlTask, cNHI_DTS {
...
virtual void Body()
{
my_helper< Index, Prio, Dir >::Run();
}
};

Hope this answers your question.

Colin
 
C

Colin Caughie

What you're trying to do here is called partial specialization;

Sorry, I just looked at your example again and realize that you're not
trying to partially specialize a function template at all, you're trying
to provide alternative implementations of a non-templated member
function depending on one of the parameters of the surrounding class
template.

This also can't be done, and the solution (or at least a possible
solution) is the same as the one I posted earlier.

Colin
 
L

Leon Pollak

Wow!!!!!!!!!
Great!!!!!!!
This is exactly what I need!!!!

Thousands of thanks!!!!!!!!!!!!
 
L

Leon Pollak

I tried the suggestion - the main obstacle of defining the Body is overcame.
But the Body itself is almost useless...:(
Each attempt to use the class data elements is impossible:
....: error: invalid use of member 'any member from the class' in static
member function

What I do incorrect?

Thanks a lot for your help.
 
C

Colin Caughie

Leon said:
I tried the suggestion - the main obstacle of defining the Body is overcame.
But the Body itself is almost useless...:(
Each attempt to use the class data elements is impossible:
...: error: invalid use of member 'any member from the class' in static
member function

What I do incorrect?

Thanks a lot for your help.

You need to do two things:

1. Pass a pointer or reference to the class instance to the helper
function. So it becomes

static DoBody( cNHI_Task& task )
{
}

then in cNHI_Task::Body you pass *this to the helper method.

2. If DoBody needs access to private or protected members of the class,
make the helper a friend:

template <int Index, int Prio, int Dir>
class cNHI_Task : public cChnlTask, cNHI_DTS {
...
friend class my_helper< Index, Prio, Dir >;
};

I think that's right anyway, I don't have a compiler close to hand today...

Colin
 
L

Leon Pollak

Colin said:
You need to do two things:

1. Pass a pointer or reference to the class instance to the helper
function. So it becomes

static DoBody( cNHI_Task& task )
{
}

then in cNHI_Task::Body you pass *this to the helper method.

2. If DoBody needs access to private or protected members of the class,
make the helper a friend:

template <int Index, int Prio, int Dir>
class cNHI_Task : public cChnlTask, cNHI_DTS {
...
friend class my_helper< Index, Prio, Dir >;
};

I think that's right anyway, I don't have a compiler close to hand
today...

Colin
Thanks Colin, a lot.
But don't you think this looks rather... well, strange? Too complex?
:)

It seems to me, that method suggested by Abhishek Padmanabh specializing
the class template is more straight forward, isn't it?
If yes, how do I eliminate the multiplication of all class elements
declarations? Isee two ways, but both are not beautiful:
- defining a macro
- deriving new class based on cNHI_Task<A,B,0>.

Thanks again.
 
C

Colin Caughie

Leon said:
Thanks Colin, a lot.
But don't you think this looks rather... well, strange? Too complex?
:)

Arguably yes, but that's often the way with C++... :) Often the best
way of doing something looks a bit weird to the uninitiated. Just look
at the Boost libraries, or even any STL implementation, to see what I mean.
It seems to me, that method suggested by Abhishek Padmanabh specializing
the class template is more straight forward, isn't it?
If yes, how do I eliminate the multiplication of all class elements
declarations? Isee two ways, but both are not beautiful:
- defining a macro
- deriving new class based on cNHI_Task<A,B,0>.

Personally I'd avoid the macro route, mainly because things that hide
behind preprocessor macros can obscure the syntax and make it difficult
for others to figure out how your code works.

The derivation route may or may not be preferable to delegating out to a
separate class. Derivation can sometimes bring with it more baggage than
you really need (e.g. the problems inherent in multiple inheritance; the
class in your example already derives from two other classes), but other
times is a useful tool. I'd recommend trying both ways and deciding
which seems cleaner to you.

Colin
 

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

No members online now.

Forum statistics

Threads
473,763
Messages
2,569,562
Members
45,038
Latest member
OrderProperKetocapsules

Latest Threads

Top