C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Specializing a class template on some criteria, CUJ June 200

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Glen Low
Guest





PostPosted: Sun Aug 22, 2004 10:46 am    Post subject: Specializing a class template on some criteria, CUJ June 200 Reply with quote



I came across Andrei Alexandrescu's interesting (if a bit spelling
challenged) article in C/C++ Users Journal (June 2004) where he has an
innovative use of SFINAE.

Often we want to specialize a class template on some criteria, rather
than on specific types. This is useful for families of types or other
situations where listing the specific types would be tedious or
impossible.

Given a compile-time boolean constant, is_something <T>::value, the
solution I used for my library macstl is (call this Method A):

template <typename T, bool b = is_something class C
{
// unspecialized
};

template <typename T> class C <T, true>
{
// specialized
};

Andrei's method in the article (call it Method B) is:

template <typename T, typename B = void> class C
{
// unspecialized
};

template <typename T> class C <T, typename enable_if ::type>
{
// specialized
};

So supposing is_something <float>::value is true, then C <float> will
be specialized.

It took me a while to grok that the SFINAEness of enable_if actually
works on class templates not just functions, but it seems Method B is
more flexible than Method A in that I can now define more cases for
specialization, instead of being tied down to the single condition in
Method A.

Questions:

1. Does Method B rely on standard C++ behavior? (I thought SFINAE is
only guaranteed for determining function overloads, not class
specializations.)

2. Does Method B work on your compiler? e.g. gcc, Metrowerks, XLC?

3. What are the pros and cons of A vs. B?

Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
David Abrahams
Guest





PostPosted: Sun Aug 22, 2004 10:55 pm    Post subject: Re: Specializing a class template on some criteria, CUJ June Reply with quote



[email]glenlow (AT) pixelglow (DOT) com[/email] (Glen Low) writes:

Quote:
Questions:

1. Does Method B rely on standard C++ behavior? (I thought SFINAE is
only guaranteed for determining function overloads, not class
specializations.)

Yes, it relies on standard behavior, as described here:

http://boost-consulting.com/boost/libs/utility/enable_if.html

and in the original paper on the topic:

http://portal.acm.org/citation.cfm?id=954186.954200

Jaakko Järvi, Jeremiah Willcock, and Andrew
Lumsdaine. Concept-controlled polymorphism. In Frank Pfennig and
Yannis Smaragdakis, editors, Generative Programming and Component
Engineering, volume 2830 of LNCS, pages 228--244. Springer Verlag,
September 2003.

--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Glen Low
Guest





PostPosted: Mon Aug 23, 2004 10:29 am    Post subject: Re: Specializing a class template on some criteria, CUJ June Reply with quote



Quote:
Yes, it relies on standard behavior, as described here:

http://boost-consulting.com/boost/libs/utility/enable_if.html

and in the original paper on the topic:

http://portal.acm.org/citation.cfm?id=954186.954200

Indeed it says so in 3.1 of the first reference.

However if you look at the Holy Standard 14.8.2/2, the paragraph
allowing SFINAE, it explicitly says (in the final draft):

"... when evaluating an explicitly specified template argument list
with respect to a given function template:"

It would seem then SFINAE is limited to function template invocations
with explicitly specified template argument lists, not to function
templates with deduced arguments, and not even to specializations of
class templates.

Or am I looking at the wrong or outdated clause of the Standard?

Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Glen Low
Guest





PostPosted: Sat Sep 04, 2004 1:47 am    Post subject: Re: Specializing a class template on some criteria, CUJ June Reply with quote

Quote:
Yes, it relies on standard behavior, as described here:

http://boost-consulting.com/boost/libs/utility/enable_if.html

Actually, the use of enable_if for partial class specialization
doesn't actually rely on SFINAE. Here's an example:

template <bool b, typename T = void> struct enable_if
{
};

template <typename T> struct enable_if <true, T>
{
typedef T type;
};

template <int i, typename Enable = void> struct X
{
static void crap () { std::cout << "do this.n"; }
};

template
{
static void crap () { std::cout << "do that.n"; }
};

int main ()
{
X <1>::crap ();
X <3>::crap ();
}

This predictably outputs

do this.
do that.

In the case of i == 1, your reference implies the specialization is
invalid but silently eliminated due to SFINAE. However if you
substitue for the first template:

template <bool b, typename T = void> struct enable_if
{
struct type { };
};

In the case of i == 1, the specialization is now valid, yet it
compiles successfully with

do this.
do that.

Since I don't think the standard mandates SFINAE for deciding on class
specialization, it's probably safer to use this variant for class
specialization (or to come up with a different name for it, perhaps).
This of course doesn't invalidate its use in function overloading.

Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com

P.S. What would really be kewl is some way of doing a partial
specialization on a series of criteria, so that the compiler selects
the best criterion just like it does now for the best type, without
embedding this information in the primary template e.g.

template <typename T, ???> class X
{
// default
};

template <typename T, criterion1 <...> > class X
{
// good
};

template <typename T, criterion2 <...> > class X
{
// better
};

template <typename T, criterion3 <...> > class X
{
// best
};

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Terje Slettebø
Guest





PostPosted: Sat Sep 04, 2004 10:46 am    Post subject: Re: Specializing a class template on some criteria, CUJ June Reply with quote

"Glen Low" <glenlow (AT) pixelglow (DOT) com> wrote

Quote:
Yes, it relies on standard behavior, as described here:

http://boost-consulting.com/boost/libs/utility/enable_if.html

Actually, the use of enable_if for partial class specialization
doesn't actually rely on SFINAE. Here's an example:

template <bool b, typename T = void> struct enable_if
{
};

template <typename T> struct enable_if <true, T
{
typedef T type;
};

template {
static void crap () { std::cout << "do this.n"; }
};

template {
static void crap () { std::cout << "do that.n"; }
};

int main ()
{
X <1>::crap ();
X <3>::crap ();
}

This predictably outputs

do this.
do that.

In the case of i == 1, your reference implies the specialization is
invalid but silently eliminated due to SFINAE. However if you
substitue for the first template:

template <bool b, typename T = void> struct enable_if
{
struct type { };
};

In the case of i == 1, the specialization is now valid, yet it
compiles successfully with

do this.
do that.

In this case, I get:

do that.
do that.

on MSVC 7.1. I.e. it always chooses the specialisation, as expected.

This shows that it was indeed SFINAE which made it output "do this.", "do
that.", earlier.

Quote:
Since I don't think the standard mandates SFINAE for deciding on class
specialization

Yes, it does. The same rules for partial ordering of templates applies to
both function templates and class template specialisations. This makes it
possible to use enable_if also for class template specialisations.

Quote:
, it's probably safer to use this variant for class
specialization (or to come up with a different name for it, perhaps).

I'm not sure I understand what you refer to as "this variant for class
specialization".

Quote:
P.S. What would really be kewl is some way of doing a partial
specialization on a series of criteria, so that the compiler selects
the best criterion just like it does now for the best type, without
embedding this information in the primary template e.g.

template <typename T, ???> class X
{
// default
};

template <typename T, criterion1 <...> > class X
{
// good
};

template <typename T, criterion2 <...> > class X
{
// better
};

template <typename T, criterion3 <...> > class X
{
// best
};

Unfortunately, as we don't have support for concepts in the language
([url]http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1510.pdf)[/url], at
least yet, use of enable_if is an on/off feature, i.e. either there's a
match, or there isn't. In other words, each of the above specialisations are
treated in isolation, as to whether or not they are included in the set of
viable specialisations. Once they are included, they don't have anything
else to order them on, so they can't be partially ordered, and it fails if
there's more than one of them.

Therefore, in the current language, you have to do something like:

template <typename T, class Enable = void> class X
{
// default
};

template <typename T, typename enable_if< criterion1 <...>::value &&
!criterion2 <...>::value && !criterion3 <...>::value >::type > class X
{
// good
};

template <typename T, typename enable_if< criterion2 <...>::value &&
!criterion1 <...>::value && !criterion3 <...>::value>::type > class X
{
// better
};

template <typename T, typename enable_if< criterion3 <...>::value &&
!criterion1 <...>::value && !criterion2 <...>::value>::type > class X
{
// best
};

I.e. manual ordering, making sure that only one specialisation can be
selected at any one time. Even so, the criteria needs to be mutually
exclusive, as well.

If we had concepts, and concept refinement, something like this might be
used:

concept Criterion1 { ... }
concept Criterion2 : Criterion1 { ... }
concept Criterion3 : Criterion2 { ... }

template<Criterion1 T>
class X
{
// good
};

template<Criterion2 T>
class X
{
// better
};

template<Criterion3 T>
class X
{
// best
};

Also note that the concepts need not be mutually exclusive here (a type
modelling the Criterion3 concept is also a model of Criterion1 and
Criterion2), and new concepts can be added, without modifying the existing
templates.

(Substituting Criterion1 with e.g. InputIterator, Criterion2 with
BidirectionalIterator and Criterion3 with RandomAccessIterator, gives some
ideas of what it can be used for)

Regards,

Terje



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Glen Low
Guest





PostPosted: Sun Sep 05, 2004 11:34 am    Post subject: Re: Specializing a class template on some criteria, CUJ June Reply with quote

Quote:
However if you
substitue for the first template:

template <bool b, typename T = void> struct enable_if
{
struct type { };
};

In the case of i == 1, the specialization is now valid, yet it
compiles successfully with

do this.
do that.

In this case, I get:

do that.
do that.

on MSVC 7.1. I.e. it always chooses the specialisation, as expected.

This shows that it was indeed SFINAE which made it output "do this.", "do
that.", earlier.

That is peculiar since X <1> is actually X <1, void> but the
specialization evaluates to X <1, T> where T is the struct declared
inside of enable_if.

Quote:
Yes, it does. The same rules for partial ordering of templates applies to
both function templates and class template specialisations. This makes it
possible to use enable_if also for class template specialisations.

Chapter and verse from the Standard, please. (I see SFINAE mentioned
in the context of resolving function templates only 14.8.2/2.)

Quote:
, it's probably safer to use this variant for class
specialization (or to come up with a different name for it, perhaps).

I'm not sure I understand what you refer to as "this variant for class
specialization".

Parse it as "this variant" "for class specialization" i.e. make a
template class like specialize_if with different types for true and
false, instead of a missing type for false.

Quote:
Therefore, in the current language, you have to do something like:

template <typename T, class Enable = void> class X
{
// default
};

template <typename T, typename enable_if< criterion1 <...>::value &&
!criterion2 <...>::value && !criterion3 <...>::value >::type > class X
{
// good
};

template <typename T, typename enable_if< criterion2 <...>::value &&
!criterion1 <...>::value && !criterion3 <...>::value>::type > class X
{
// better
};

template <typename T, typename enable_if< criterion3 <...>::value &&
!criterion1 <...>::value && !criterion2 <...>::value>::type > class X
{
// best
};

I.e. manual ordering, making sure that only one specialisation can be
selected at any one time. Even so, the criteria needs to be mutually
exclusive, as well.

The problem here is that each partial specialization then needs to
know about the rest to ensure exclusivity. The reason I liked this
approach was that the single partial specialization could declare
criteria independent of the primary template (a flaw with with OP
idea), but it doesn't scale to multiple overlapping partial
specializations.

I have a germ of an idea, but need more brains to flesh it out.

If you have a series of partial specializations on T*, T**, T***,
T**** then the ones with more * override the ones with less *
predictably. So if you could get the criterion to "somehow" put out a
partial specialization on a certain number of *, then it would
predictably override (or be overridden) by other criterion-based
partial specializations. Each criterion would match on the condition
and give a value that is mapped to a certain number of *. This
maintains some independence, so for example you could put n partial
specializations in a header file and another m partial specializations
in another header file without the first n needing to exclude the
other m.

Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.