Specializing template members for pointer types.

J

jason.cipriani

If I have a template class with a member function:

template <typename T> class C {
void member ();
};

template <typename T> void C<T>::member () {
}

Is there some way to make a specialized implementation of member()
that is used when T is any pointer type?

Thanks,
Jason
 
M

Michael DOUBEZ

(e-mail address removed) a écrit :
If I have a template class with a member function:

template <typename T> class C {
void member ();
};

template <typename T> void C<T>::member () {
}

Is there some way to make a specialized implementation of member()
that is used when T is any pointer type?

Not directly. You would have to specialize the outer class.

The way is to use overload:
1. You have to have a predicate telling you whether or not a type is a
pointer:
template <typename T>
struct is_pointer
{
static const bool value=false;
};
template <typename T>
struct is_pointer<T*>
{
static const bool value=true;
};
2. And then an operator to transform this operation into a type:
template<typename T,bool b=is_pointer<T>::value >
struct is_pointer_type{};
3. And then, use overloading
template <typename T> struct C {
void member ()
{ return member(is_pointer_type<T>());}

void member(const is_pointer_type<T,true>&);
void member(const is_pointer_type<T,false>&);
};
You can make the distinction:
template <typename T> void C<T>::member(const is_pointer_type<T,false>&)
{
cout<<"Not a pointer"<<endl;
}
template <typename T> void C<T>::member (const is_pointer_type<T,true>&)
{
cout<<"Is a pointer"<<endl;
}

Normaly, the extra call and parameter are optimized out.
 
M

Michael DOUBEZ

Michael DOUBEZ a écrit :
(e-mail address removed) a écrit :

Not directly. You would have to specialize the outer class.

The way is to use overload:
1. You have to have a predicate telling you whether or not a type is a
pointer:
template <typename T>
struct is_pointer
{
static const bool value=false;
};
template <typename T>
struct is_pointer<T*>
{
static const bool value=true;
};
[snip]
If your specializations are syntaxically correct when used with T or T*
(by example if you never deference the pointer), you can simply define:

template <typename T> void C<T>::member()
{
if(is_pointer<T>::value){
//T is a pointer
}
else {
//T is not a pointer
}
}

It won't clutter the interface and the dead code should be removed at
compile time.
 
J

jason.cipriani

(e-mail address removed) a écrit :





Not directly. You would have to specialize the outer class.

The way is to use overload:
1. You have to have a predicate telling you whether or not a type is a
pointer:
template <typename T>
struct is_pointer
{
     static const bool value=false;};

template <typename T>
struct is_pointer<T*>
{
     static const bool value=true;};

2. And then an operator to transform this operation into a type:
template<typename T,bool b=is_pointer<T>::value >
struct is_pointer_type{};
3. And then, use overloading
template <typename T> struct C {
       void member ()
       { return member(is_pointer_type<T>());}

       void member(const is_pointer_type<T,true>&);
       void member(const is_pointer_type<T,false>&);};

You can make the distinction:
template <typename T> void C<T>::member(const is_pointer_type<T,false>&)
{
     cout<<"Not a pointer"<<endl;}

template <typename T> void C<T>::member (const is_pointer_type<T,true>&)
{
     cout<<"Is a pointer"<<endl;

}

Normaly, the extra call and parameter are optimized out.


Thanks; I never would have thought to do it that way.

Jason
 
F

Fraser Ross

"Michael DOUBEZ"
Not directly. You would have to specialize the outer class.

Yes thats a full specialisation not a partial specialisation of a member
function which can't be done.

The Loki library has the classes Int2Type and TypeTraits that could be
used. Is that where you got the idea?

Fraser.
 
J

joe

Michael DOUBEZ a écrit :
Is there some way to make a specialized implementation of member()
that is used when T is any pointer type?> [snip]
If your specializations are syntaxically correct when used with T or T*
(by example if you never deference the pointer), you can simply define:

template <typename T> void C<T>::member()
{
  if(is_pointer<T>::value){
     //T is a pointer
  }
  else {
     //T is not a pointer
  }

}

Or likewise use these:
template<typename T>
struct is_pointer
{
operator bool(){return false;}
};
struct is_pointer<T*>
{
operator bool(){return true;}
};

Then use:
if(is_pointer<T>()), wherever you like.

Joe C
 
F

Fraser Ross

"Michael DOUBEZ"
If your specializations are syntaxically correct when used with T or T*
(by example if you never deference the pointer), you can simply define:

template <typename T> void C<T>::member()
{
if(is_pointer<T>::value){
//T is a pointer
}
else {
//T is not a pointer
}
}

It won't clutter the interface and the dead code should be removed at
compile time.

Isn't the code for true and false going to be compiled even if it isn't
used? That might be a problem.

Fraser.
 
A

Andrey Tarasevich

joe said:
Or likewise use these:
template<typename T>
struct is_pointer
{
operator bool(){return false;}
};
struct is_pointer<T*>
{
operator bool(){return true;}
};

Then use:
if(is_pointer<T>()), wherever you like.

The deeper you hide the compile-time constant ('true' or 'false' in this
case), the greater is the chance that the compiler won't be able to
unroll the whole thing and figure out what part of the code can be
thrown out.

Much of the value of 'if' based solution suggested by Michael is in the
fact that the conditional expression in the 'if' is an immediately
obvious compile-time constant, which will make virtually any compiler to
remove the condition checking entirely and generate code only for the
relevant branch of the former 'if'.

What you suggest is more "risky" in this regard. I won't be surprised to
discover that some compilers do actually generate a full-blown condition
checking and code for both branches if the 'if' in response to your code.
 
A

Andrey Tarasevich

Fraser said:
"Michael DOUBEZ"

Isn't the code for true and false going to be compiled even if it isn't
used? That might be a problem.

That's what is meant by the above "if your specializations are
syntaxically correct when used with T or T*".
 
F

Fraser Ross

"Andrey Tarasevich" > Much of the value of 'if' based solution suggested
by Michael is in the
fact that the conditional expression in the 'if' is an immediately
obvious compile-time constant, which will make virtually any compiler to
remove the condition checking entirely and generate code only for the
relevant branch of the former 'if'.

I've read what he said again and he is saying that the code for both
branches has to be syntactically correct for T and *T. I don't think
you should try to expect a compiler not to compile both branches.

Fraser.
 
A

Andrey Tarasevich

Fraser said:
I've read what he said again and he is saying that the code for both
branches has to be syntactically correct for T and *T. I don't think
you should try to expect a compiler not to compile both branches.

It is not about whether the compiler will "compile" both branches. It
will, of course, meaning that both branches have to be well-formed. It
is about the compiler generating (or not generating) the actual run-time
code for one of the branches.

It is perfectly reasonable to expect that code like

if (true) {
/* ... */
}
else {
/* ... */
}

will be reduced to just the true branch without any condition checking
in the final generated code. Of course, at the compilation stage both
branches will be "compiled", i.e. checked for their "well-formedness".
 
K

Kai-Uwe Bux

Fraser said:
"Andrey Tarasevich" > Much of the value of 'if' based solution suggested
by Michael is in the

I've read what he said again and he is saying that the code for both
branches has to be syntactically correct for T and *T. I don't think
you should try to expect a compiler not to compile both branches.

There is a difference between a compiler compiling and a compiler including
object code that can be eliminated. Of course, the compiler will read both
branches. It will also generate code for an internal representation. But as
soon as it comes to the dead code elimination phase while optimizing, the
compiler will cut out the code in the if-false branch (at least the
techniques for doing that have been known for a long time and are described
in the literature on compiler writing).


Best

Kai-Uwe Bux
 
F

Fraser Ross

I know the unused branch would be optimised out.

You are better off using the earlier technique of overloading. There
isn't a problem with syntactic correctness with it.

Fraser.
 
A

Andrey Tarasevich

Fraser said:
You are better off using the earlier technique of overloading. There
isn't a problem with syntactic correctness with it.

Firstly, there's really no discussion about what's "better" in this
case. The point of the whole thing is to demonstrate the various
approaches that can be used. Each approach has its pros and cons. Each
approach has its own set of circumstances it is best suited for.

Secondly, the overloading technique is only appropriate when
more-or-less major abstract functionality is getting replaced for
pointer types. But when it comes to minor, possibly cosmetic
differences, the branching technique might work much better and produce
significantly less obfuscated code.
 
J

joecook

Firstly, there's really no discussion about what's "better" in this
case. The point of the whole thing is to demonstrate the various
approaches that can be used. Each approach has its pros and cons. Each
approach has its own set of circumstances it is best suited for.

Secondly, the overloading technique is only appropriate when
more-or-less major abstract functionality is getting replaced for
pointer types. But when it comes to minor, possibly cosmetic
differences, the branching technique might work much better and produce
significantly less obfuscated code.

Agreed, totally.
 
J

joecook

The deeper you hide the compile-time constant ('true' or 'false' in this
case), the greater is the chance that the compiler won't be able to
unroll the whole thing and figure out what part of the code can be
thrown out.

Much of the value of 'if' based solution suggested by Michael is in the
fact that the conditional expression in the 'if' is an immediately
obvious compile-time constant, which will make virtually any compiler to
remove the condition checking entirely and generate code only for the
relevant branch of the former 'if'.

What you suggest is more "risky" in this regard. I won't be surprised to
discover that some compilers do actually generate a full-blown condition
checking and code for both branches if the 'if' in response to your code.

You are right of course; I guess I've been spoiled in this regard, but
I suspect most decent compilers will make this a compile time decision
as gcc does. All compilers must decide at compile-time which of the
two functions to call, so the only wiggle room is whether the compiler
decides to inline the "return true" or "return false". I suspect any
compiler worth 1 cent will inline in this case.

Thanks,
Joe Cook
 
A

alfps

If I have a template class with a member function:

template <typename T> class C {
  void member ();

};

template< typename T > class CSpecializations
{
static void member( C& ) {}
};

template< typename T > class CSpecializations< T* >
{
static void member( C& ) {}
}

template <typename T> void C<T>::member () {

CSpecializations said:
}

Is there some way to make a specialized implementation of member()
that is used when T is any pointer type?

C above.


Cheers & hth.,

- Alf
 
M

Michael DOUBEZ

Fraser Ross a écrit :
"Michael DOUBEZ"

Yes thats a full specialisation not a partial specialisation of a member
function which can't be done.

The Loki library has the classes Int2Type and TypeTraits that could be
used. Is that where you got the idea?

Yes. Reading "Modern C++".
 

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,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top