VC 7.0 template specialization problems

The following specialization fails to compile on .NET 2002. Is there a good reason as to why, and if not, is there a suggested work around? template < typename T > class A { }; template < typename T > class B { }; template < typename T > class A < B < T > > // this is the specialization { }; -Jason Hise

Jason Hise wrote:
The following specialization fails to compile on .NET 2002. Is there a good reason as to why, and if not, is there a suggested work around?
template < typename T > class A { };
template < typename T > class B { };
template < typename T > class A < B < T > > // this is the specialization { };
This is partial specialization, which VC didn't support until version 7.1. If you're working from scratch, there are some workarounds using nested templates; see, e.g., http://www.boost.org/boost/pending/ct_if.hpp. Using mpl, you might do: template<typename T> struct is_B; template<typename T> struct A_primary { /* ... */ }; template<typename T> struct A_specialized { /* ... */ }; template<typename T> struct A : mpl::if_< is_B<T>, A_primary <T>, A_specialized<T> >::type { /* Ctors, etc. */ } Here it is often sufficient to implement is_B<> using the "sizeof trick". If you are the author of B, and you need is_B<T> to be defined exactly, you can give B<T> a typedef identifying T and use is_same<> together with has_xxx from mpl. I'd say more but I have to run. Jonathan

Jonathan Turkanis wrote:
Jason Hise wrote:
The following specialization fails to compile on .NET 2002. Is there a good reason as to why, and if not, is there a suggested work around?
template < typename T > class A { };
template < typename T > class B { };
template < typename T > class A < B < T > > // this is the specialization { };
This is partial specialization, which VC didn't support until version 7.1.
If you're working from scratch, there are some workarounds using nested templates; see, e.g., http://www.boost.org/boost/pending/ct_if.hpp.
Using mpl, you might do:
template<typename T> struct is_B;
template<typename T> struct A_primary { /* ... */ };
template<typename T> struct A_specialized { /* ... */ };
template<typename T> struct A : mpl::if_< is_B<T>, A_primary <T>, A_specialized<T> >::type { /* Ctors, etc. */ }
Here it is often sufficient to implement is_B<> using the "sizeof trick". If you are the author of B, and you need is_B<T> to be defined exactly, you can give B<T> a typedef identifying T and use is_same<> together with has_xxx from mpl. I'd say more but I have to run.
Jonathan
Here's the context of my question: I recently added a new lifetime policy for my singleton class. However, instead of providing an interface which the general definition of singleton accepts, it is an empty class. Directly underneath this empty class I provide a partial specialization of singleton in which all the changes are made. It is a partial specialization because all of my lifetime policies have sub policies of their own. I do this because the general version of the singleton definition will automatically have the overhead of maintaining the lifetime of the lifetime, which is unnecessary overhead for this policy and actually gets in the way (the whole point of this lifetime policy is to be as low overhead as possible). Right now, this policy class and the specialization it offers are in a separate include file from the primary singleton definition. My fear is that the method above will require that both implementations be defined in the same include file, and be tightly bound together, making the code less organized and more difficult to maintain. Would it be terrible of me to disable compilation of this lifetime in cases when partial template specialization is not supported? (And if so, what boost macro should I check?) Another lifetime exists which essentially offers the same functional behavior (destruction in reverse order of creation). The only difference is that it has more overhead in terms of memory usage (another hidden singleton living in the background), and as a result has a few more features (can create and destroy at an arbitrary time) and is a bit safer to use (supports phoenix behavior). When space is not an issue, losing this new lifetime will not really result in the loss of any features. Is it worth uglifying my code to support a low overhead lifetime on compilers that do not support partial template specialization? Should this question wait until the formal singleton review? -Jason

Here's the context of my question: I recently added a new lifetime policy for my singleton class. However, instead of providing an interface which the general definition of singleton accepts, it is an empty class. Directly underneath this empty class I provide a partial specialization of singleton in which all the changes are made. It is a partial specialization because all of my lifetime policies have sub policies of their own. I do this because the general version of the singleton definition will automatically have the overhead of maintaining the lifetime of the lifetime, which is unnecessary overhead for
Jason Hise wrote: this
policy and actually gets in the way (the whole point of this lifetime policy is to be as low overhead as possible). Right now, this policy class and the specialization it offers are in a separate include file from the primary singleton definition. My fear is that the method above will require that both implementations be defined in the same include file, and be tightly bound together, making the code less organized and more difficult to maintain.
Would it be terrible of me to disable compilation of this lifetime in cases when partial template specialization is not supported?
No -- in fact you're free to disregard such compilers if you want.
(And if so, what boost macro should I check?)
BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
Another lifetime exists which essentially offers the same functional behavior (destruction in reverse order of creation). The only difference is that it has more overhead in terms of memory usage (another hidden singleton living in the background), and as a result has a few more features (can create and destroy at an arbitrary time) and is a bit safer to use (supports phoenix behavior). When space is not an issue, losing this new lifetime will not really result in the loss of any features.
Is it worth uglifying my code to support a low overhead lifetime on compilers that do not support partial template specialization? Should this question wait until the formal singleton review?
You might be able to implement this policy without partial specialization, using the tricks I discussed; however, there's no need to do so if you don't want to. It sounds like all you need to do may be to add an #error directive if the header containing the new lifetime policy is included but the compiler doesn't support partial specialization. Jonathan

"Jason Hise" <chaos@ezequal.com> wrote
The following specialization fails to compile on .NET 2002. Is there a good reason as to why, and if not, is there a suggested work around?
template < typename T > class A { };
template < typename T > class B { };
template < typename T > class A < B < T > > // this is the specialization { };
I don't think VC7.0 supports partial template specialization. The only workaround I know would be to use function template overloading. template<class T> void foo(const B<T>&); // this should compile Depending on what you actually want to do, this may or may not help. Regards, Arkadiy
participants (3)
-
Arkadiy Vertleyb
-
Jason Hise
-
Jonathan Turkanis