Partial template class specialization?

M

MikeWhy

I want to override a template class method on a formal parameter. Is this
possible without redefining everything else in the class? The alternative is
a "conditional is constant" warning. For example, call Reset() only when
AutoReset is true:

template <bool AutoReset, class T>
class TimerNode {
....
void OnTimer();
void DoCall();
};
//----------------------
template <class T>
void TimerNode<true, T>::OnTimer()
{
Reset();
DoCall();
}
//----------------------
template <class T>
void TimerNode<false, T>::OnTimer()
{ DoCall();
}

MSVC 2008 complains:
error C3860: template argument list following class template name must list
parameters in the order used in template parameter list
error C3855: 'CallbackTimerT<AutoReset,TickProc>': template parameter
'AutoReset' is incompatible with the declaration

error C2976: 'CallbackTimerT<AutoReset,TickProc>' : too few template
arguments

error C3860: template argument list following class template name must list
parameters in the order used in template parameter list
 
V

Victor Bazarov

I want to override a template class method on a formal parameter. Is
this possible without redefining everything else in the class? The
alternative is a "conditional is constant" warning. For example, call
Reset() only when AutoReset is true:

template <bool AutoReset, class T>
class TimerNode {
...
void OnTimer();
void DoCall();
};
//----------------------
template <class T>
void TimerNode<true, T>::OnTimer()
{
Reset();
DoCall();
}
//----------------------
template <class T>
void TimerNode<false, T>::OnTimer()
{ DoCall();
}

Why do you think you need this dance? Is "Reset" name not available
when 'TimerNode' is instantiated with 'AutoReset==false'? If it is
available all the time, just do

template<bool AR, class T> void TimerNode<AR,T>::OnTimer()
{
if (AR) Reset();
DoCall();
}

IOW, why create a problem for yourself where there isn't one?
MSVC 2008 complains:
error C3860: template argument list following class template name must
list parameters in the order used in template parameter list
error C3855: 'CallbackTimerT<AutoReset,TickProc>': template parameter
'AutoReset' is incompatible with the declaration

error C2976: 'CallbackTimerT<AutoReset,TickProc>' : too few template
arguments

error C3860: template argument list following class template name must
list parameters in the order used in template parameter list

V
 
N

Noah Roberts

I want to override a template class method on a formal parameter. Is
this possible without redefining everything else in the class? The
alternative is a "conditional is constant" warning. For example, call
Reset() only when AutoReset is true:

template <bool AutoReset, class T>
class TimerNode {
...
void OnTimer();
void DoCall();
};
//----------------------
template <class T>
void TimerNode<true, T>::OnTimer()
{
Reset();
DoCall();
}
//----------------------
template <class T>
void TimerNode<false, T>::OnTimer()
{ DoCall();
}

MSVC 2008 complains:
error C3860: template argument list following class template name must
list parameters in the order used in template parameter list
error C3855: 'CallbackTimerT<AutoReset,TickProc>': template parameter
'AutoReset' is incompatible with the declaration

error C2976: 'CallbackTimerT<AutoReset,TickProc>' : too few template
arguments

error C3860: template argument list following class template name must
list parameters in the order used in template parameter list

These errors are not very helpful. The problem is that you're not
allowed to partially specialize functions.
 
M

MikeWhy

Victor said:
Why do you think you need this dance? Is "Reset" name not available
when 'TimerNode' is instantiated with 'AutoReset==false'? If it is
available all the time, just do

template<bool AR, class T> void TimerNode<AR,T>::OnTimer()
{
if (AR) Reset();
DoCall();
}

IOW, why create a problem for yourself where there isn't one?

The compiler should optimize away the conditional for this simple case, of
course. But it isn't difficult to imagine it useful for something other than
a boolean. Specializing on just one or a few typename Foo rather than the
bool here would be the use case. I'll be darned if I can contrive an example
this moment, though.
 
V

Victor Bazarov

The compiler should optimize away the conditional for this simple case,
of course. But it isn't difficult to imagine it useful for something
other than a boolean. Specializing on just one or a few typename Foo
rather than the bool here would be the use case. I'll be darned if I can
contrive an example this moment, though.

You would have to partially specialise the entire template in that case.
Or you could define a helper template (class or function). The
specifics of the solution depend on the problem, of course.

V
 
Q

Qi

template <bool AutoReset, class T>
class TimerNode {
...
void OnTimer();
void DoCall();
};
//----------------------
template <class T>
void TimerNode<true, T>::OnTimer()
{
Reset();
DoCall();
}
//----------------------
template <class T>
void TimerNode<false, T>::OnTimer()
{ DoCall();
}


You can only partial specialize template.
You need to split TimerNode to two templates,
TimerNodeBase and TimerNode (inherited from TimerNodeBase).
Then put OnTimer in TimerNode and partial specialize TimerNode.
 
M

MikeWhy

Qi said:
You can only partial specialize template.
You need to split TimerNode to two templates,
TimerNodeBase and TimerNode (inherited from TimerNodeBase).
Then put OnTimer in TimerNode and partial specialize TimerNode.

Does that actually change anything? I can separate the classes as you say,
but it still has the problem of partial specialization.

template <typename T> class TimerNodeBase {...};

template <bool AutoReset, typename T>
class TimerNode : public TimerNodeBase<T> {...}; // as before.

template <> void TimerNode<true>::OnTimer(){ ... } // problems, as before
template <> void TimerNode<false>::OnTimer(){ ... } // problems, as before



The full context is as follows. TimerNode is embedded in class
CallbackTimer, templatized on its calllback client. They pre-existed that
way with auto-reset being the default and only behavior. I wanted to add an
option to just unlink from the timer and not auto-reset, hence the new

template <typename T, bool AutoReset = true>
class CallbackTimer
{
...
struct TimerNode; // as before.

private:
DoubleLinkedList<TimerNode> timers;
};

It would be nice to have that supported simply in the language. I haven't
checked the more recent language proposed standard.
 
V

Victor Bazarov

Does that actually change anything? I can separate the classes as you
say, but it still has the problem of partial specialization.

template <typename T> class TimerNodeBase {...};

template <bool AutoReset, typename T>
class TimerNode : public TimerNodeBase<T> {...}; // as before.

template <> void TimerNode<true>::OnTimer(){ ... } // problems, as before
template <> void TimerNode<false>::OnTimer(){ ... } // problems, as before



The full context is as follows. TimerNode is embedded in class
CallbackTimer, templatized on its calllback client. They pre-existed
that way with auto-reset being the default and only behavior. I wanted
to add an option to just unlink from the timer and not auto-reset, hence
the new

template <typename T, bool AutoReset = true>
class CallbackTimer
{
...
struct TimerNode; // as before.

private:
DoubleLinkedList<TimerNode> timers;
};

It would be nice to have that supported simply in the language. I
haven't checked the more recent language proposed standard.

Get a copy of the "Modern C++ Design" by Alexandrescu. What you seem to
want to do is to make your resetting feature optional. Policy fits
right into that. Essentially you write

template<typename T, typename ResetPolicy>
class CallbackTimer
{
...
void OnTimer() {
ResetPolicy::Reset(this); // if you need anything
DoCall
}
};

struct ResetPolicyReset
{
template<class T> static void Reset(T* pCBTimer) {
pCBTimer->Reset();
}
};

struct ResetPolicyDontReset
{
static void Reset(void*) {} // do nothing
};

...
// when you need a timer that resets:
CallbackTimer<TickProc, ResetPolicyReset> resettingTimer;

// when you need a timer that doesn't reset:
CallbackTimer<TickProc, ResetPolicyDontReset> plainTimer;

Now, just like with the 'if (bReset)' that we discussed before, you have
to rely on the compiler to not generate code that is not needed.

Policy-based design (like type traits, too) rely on the compiler's
ability to refrain from generating code when it's not needed. Try it.

V
 
F

Francesco

Get a copy of the "Modern C++ Design" by Alexandrescu.  What you seem to
want to do is to make your resetting feature optional.  Policy fits
right into that.  Essentially you write

     template<typename T, typename ResetPolicy>
     class CallbackTimer
     {
     ...
         void OnTimer() {
            ResetPolicy::Reset(this); // if you need anything
            DoCall
         }
     };

     struct ResetPolicyReset
     {
         template<class T> static void Reset(T* pCBTimer) {
             pCBTimer->Reset();
         }
     };

     struct ResetPolicyDontReset
     {
         static void Reset(void*) {} // do nothing
     };

     ...
     // when you need a timer that resets:
       CallbackTimer<TickProc, ResetPolicyReset>  resettingTimer;

     // when you need a timer that doesn't reset:
       CallbackTimer<TickProc, ResetPolicyDontReset> plainTimer;

Now, just like with the 'if (bReset)' that we discussed before, you have
to rely on the compiler to not generate code that is not needed.

Policy-based design (like type traits, too) rely on the compiler's
ability to refrain from generating code when it's not needed.  Try it.

V

Hi,
or you can try something like:

// code
#include <iostream>

template< int K >
struct CTypeFromInt
{};

template <bool AutoReset, class T>
class TimerNode {
public:
void Reset() { std::cout << __func__ << std::endl; };
void ConditionalAutoReset( CTypeFromInt< true > ) { Reset(); }
void ConditionalAutoReset( CTypeFromInt< false > ) { }
void OnTimer()
{ ConditionalAutoReset( CTypeFromInt< AutoReset >()); DoCall();}
void DoCall() {}
};


int main()
{
TimerNode< true, int > obj1;
obj1.OnTimer();
std::cout << "---\n";
TimerNode< false, int > obj2;
obj2.OnTimer();

}
// end code
 
M

MikeWhy

Victor Bazarov said:
Get a copy of the "Modern C++ Design" by Alexandrescu. What you seem to
want to do is to make your resetting feature optional. Policy fits right
into that. Essentially you write

template<typename T, typename ResetPolicy>
class CallbackTimer
{
...
void OnTimer() {
ResetPolicy::Reset(this); // if you need anything
DoCall
}
};

struct ResetPolicyReset
{
template<class T> static void Reset(T* pCBTimer) {
pCBTimer->Reset();
}
};

struct ResetPolicyDontReset
{
static void Reset(void*) {} // do nothing
};

...
// when you need a timer that resets:
CallbackTimer<TickProc, ResetPolicyReset> resettingTimer;

// when you need a timer that doesn't reset:
CallbackTimer<TickProc, ResetPolicyDontReset> plainTimer;

Now, just like with the 'if (bReset)' that we discussed before, you have
to rely on the compiler to not generate code that is not needed.

Policy-based design (like type traits, too) rely on the compiler's ability
to refrain from generating code when it's not needed. Try it.

Thanks, and to Francesco as well. I actually read Alexandrescu's years ago
(7 years? 8? Time surely does fly.) ResetPolicy is the right way to do it.
Again, thanks.
 

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,019
Latest member
RoxannaSta

Latest Threads

Top