Topic: Specialization of template members of template classes
Author: igodardA@TpacbellDO.Tnet ("Ivan Godard")
Date: Thu, 13 May 2004 03:36:06 +0000 (UTC) Raw View
This seems too esoteric to draw a response on comp.lang.c++.moderated,
trying here.
Consider:
template<typename A> struct B {
template<typename C> struct D {};
template<> struct D<signed char> { typedef signed short R; };
template<> struct D<unsigned char> { typedef unsigned short R; };
template<> struct D<signed short> { typedef signed int R; };
template<> struct D<unsigned short> { typedef unsigned int R; };
typename D<A>::R v;
};
The purpose is to have a local template that does some type computation
(here to return the type next larger than its argument) which is then used
in the enclosing class, by providing specializations of the local class that
address all argument types of interest. Note that the local template has no
dependence on the enclosing template B nor its argument A. This fails to
compile; g++ complains that you can't specialize a local template inside a
class.
So you move all the specializations outside:
template<typename A> struct B {
template<typename C> struct D {};
typename D<A>::R v;
};
template<> template<typename T>struct B<T>::D<signed char> { typedef signed
short R; };
template<> template<typename T>struct B<T>::Dstruct B<unsigned char> {
typedef unsigned short R; };
template<> template<typename T>struct B<T>::Dstruct B<signed short> {
typedef signed int R; };
template<> template<typename T>struct B<T>::Dstruct B<unsigned short> {
typedef unsigned int R; };
This too fails to compile; g++ complains that the specialization does not
depend on T.
I reported these as bugs to g++, and they assert that the behavior is
correct by the standard. I'm willing to believe that, but would like to know
why the standard bans this construction, which seems straightforward,
useful, and easy to compile. Also, is there an alternative formulation that
achieves the desired goal? (Yes, the template D and its specializations can
be moved to file scope, which is my present workaround, but that pollutes
the
namespace.)
Ivan
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dsp@bdal.de (=?ISO-8859-1?Q?=22Daniel_Kr=FCgler_=28nee_Spangenberg=29=22?=)
Date: Thu, 13 May 2004 10:29:41 +0000 (UTC) Raw View
Good morning, Ivan Godard,
Ivan Godard schrieb:
[..]
>So you move all the specializations outside:
>
>template<typename A> struct B {
> template<typename C> struct D {};
> typename D<A>::R v;
>};
>template<> template<typename T>struct B<T>::D<signed char> { typedef signed
>short R; };
>template<> template<typename T>struct B<T>::Dstruct B<unsigned char> {
>typedef unsigned short R; };
>template<> template<typename T>struct B<T>::Dstruct B<signed short> {
>typedef signed int R; };
>template<> template<typename T>struct B<T>::Dstruct B<unsigned short> {
>typedef unsigned int R; };
>
>This too fails to compile; g++ complains that the specialization does not
>depend on T.
>
>I reported these as bugs to g++, and they assert that the behavior is
>correct by the standard. I'm willing to believe that, but would like to know
>why the standard bans this construction, which seems straightforward,
>useful, and easy to compile. Also, is there an alternative formulation that
>achieves the desired goal? (Yes, the template D and its specializations can
>be moved to file scope, which is my present workaround, but that pollutes
>the
>namespace.)
>
>
I think the reason for banning this construction is due to the fact,
that you have to consider, that potentially
everyone could (partially) specialize the class template B. Now, if you
realize that such a specialization could
remove any member class templates D (or substitute them by other items
of name D) you will understand,
that in those cases the compiler would have a problem. I think the
problem could be solved by an ordering
mechanism (lets say, any outer specializations overwrites inner
specializations) but I don't know whether this
would not lead to other problems...)
Hope that helps,
Daniel
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: AlbertoBarbati@libero.it (Alberto Barbati)
Date: Thu, 13 May 2004 10:29:49 +0000 (UTC) Raw View
Ivan Godard wrote:
> I reported these as bugs to g++, and they assert that the behavior is
> correct by the standard. I'm willing to believe that, but would like to know
> why the standard bans this construction, which seems straightforward,
> useful, and easy to compile.
It does not look so straightforward, useful and easy to compile, to me.
Just my opinion, though ;-)
> Also, is there an alternative formulation that
> achieves the desired goal? (Yes, the template D and its specializations can
> be moved to file scope, which is my present workaround, but that pollutes
> the namespace.)
What about:
namespace B_details {
template<typename C> struct D {};
template<> struct D<signed char> { typedef signed short R; };
template<> struct D<unsigned char> { typedef unsigned short R; };
template<> struct D<signed short> { typedef signed int R; };
template<> struct D<unsigned short> { typedef unsigned int R; };
};
template<typename A> struct B {
typename B_details::D<A>::R v;
};
Alberto
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: richard@ex-parrot.com (Richard Smith)
Date: Thu, 13 May 2004 15:14:44 +0000 (UTC) Raw View
igodardA@TpacbellDO.Tnet ("Ivan Godard") wrote in message news:<caAoc.47757$ur3.7396@newssvr29.news.prodigy.com>...
> This seems too esoteric to draw a response on comp.lang.c++.moderated,
> trying here.
>
> Consider:
>
> template<typename A> struct B {
> template<typename C> struct D {};
> template<> struct D<signed char> { typedef signed short R; };
This is not legal for two reasons. First, explicit specialisations
may not be declared at class scope (some compilers do accept them,
however). (See 14.7.3/2: "An explicit specialization shall be
declared in the namespace of which the template is a member, or, for
member templates, in the namespace of which the enclosing class or
enclosing class template is a member.")
Second, you can only expicitly specialise a member template for a
specific instantiation of the (outer) template class. That is, if you
want to specialise B<A>::D<C> for some C, you must also do it for a
specified A too.
If you want to specialise B<int>::D<signed char>, the declaration
would look like this:
template <> template <>
struct B<int>::D<signed char> {
typedef signed short R;
};
If you need to constrain C but not A, then you will have to use
another mechanism, for example delegating to a namespace scope
template:
namespace Details {
template <typename A, typename C> struct B_D {};
}
template<typename A> struct B {
template<typename C> struct D : Details::B_D<A,C> {};
}
// Specialisations go here:
namespace Details {
template <typename A> struct B_D<A, signed char> {
typedef signed short R;
};
}
> Note that the local template has no
> dependence on the enclosing template B nor its argument A.
So why is it a member template? (Note: the term is member template,
not local template.) By making it a member template, you get a
separate instantiation for each pair (A,C); if the value of A is
irrelevant, this will likely lead to code bloat.
> This fails to
> compile; g++ complains that you can't specialize a local template inside a
> class.
As indeed it should.
> So you move all the specializations outside:
>
> template<typename A> struct B {
> template<typename C> struct D {};
> typename D<A>::R v;
> };
> template<> template<typename T>struct B<T>::D<signed char> { typedef signed
> short R; };
[...]
> This too fails to compile; g++ complains that the specialization does not
> depend on T.
Again, quite correctly for the second reason I mentioned above. You
also have the wrong syntax. Were what you want to do legal, I *think*
the syntax would be as follows:
template <typename T> template <>
struct B<T>::D<signed char> { /* ... */ };
This question, and many related issues, are covered in Vandevoorde and
Josuttis' definitive book "C++ Templates: The Complete Guide".
Section 12.3 covers this particular issue. I stongly recommend
obtaining a copy.
> I'm willing to believe that, but would like to know
> why the standard bans this construction, which seems straightforward,
> useful, and easy to compile.
Straightforward? That's not the word I would have used.
As to whether it's "easy to compile", it would add various extra
complications to do with partial ordering. For example, if I have two
specialisations,
template <> template <class C>
struct B<int>::D { enum {I=2}; };
template <class A> template <>
struct B<A>::D<signed char> { enum {I=3}; };
Now, what is B<int>::D<signed char>::I? I would probably expect it
to be 2, as I would expect the specialisation of B<int>::D to replace
both the primary template B<A>::D and all its specialisations; but
equally, others might expect partial ordering to flag an ambiguity in
this case.
Resolving this would require extra complication in an already complex
section of the Standard as well as additional inteligence in the
compiler. Frankly, I can't see the worth of it.
--
Richard Smith
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]