 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Glen Low Guest
|
Posted: Tue Mar 02, 2004 11:32 am Post subject: Compile-time dispatch using types vs. constant integral expr |
|
|
The old SGI STL (still living in gcc) had a lot of code partially
specialized on __true_type and __false_type, and then had code that
dispatched to the correct specialization based on some compile-time
info e.g. trivial constructor. In cpp_type_traits.h in libstdc++,
Gabriel Dos Reis (and I think boost) advocates dispatch based on
constant integral expressions that evaluate to 1 or 0, instead of
types.
What are the pros and cons of the different approaches? Does it help
much with compilation times especially overload resolution?
In particular, consider the following type-based dispatch:
template <typename T> void perform (T t, __true_type)
{
// code that is only valid if discriminate <T>::type is __true_type
}
template <typename T> void perform (T t, __false_type)
{
// code that is only valid if discriminate <T>::type is __false_type
}
template <typename T> void perform (T t)
{
perform (t, typename discriminate <T>::type ());
}
Because the code in perform (T, __true_type) is only valid if
discriminate <T>::type is true, you can't use the neater formulation:
template <typename T> void perform (T t)
{
if (discriminate <T>::value)
// code that is only valid if discriminate <T>::value is true
else
// code that is only valid if discriminate <T>::value is false
}
Instead it seems you have to resort to a clumsy dispatch over an
external class structure and specialization which essentially mimics
the type-based approach, but only has the minor advantage of not
invoking overload resolution. Is there any neat way to achieve a
single function like the above?
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 |
|
 |
Stephen C. Dewhurst Guest
|
Posted: Tue Mar 02, 2004 2:24 pm Post subject: Re: Compile-time dispatch using types vs. constant integral |
|
|
On 2 Mar 2004 06:32:39 -0500, [email]glenlow (AT) pixelglow (DOT) com[/email] (Glen Low) wrote:
| Quote: | The old SGI STL (still living in gcc) had a lot of code partially
specialized on __true_type and __false_type, and then had code that
dispatched to the correct specialization based on some compile-time
info e.g. trivial constructor. In cpp_type_traits.h in libstdc++,
Gabriel Dos Reis (and I think boost) advocates dispatch based on
constant integral expressions that evaluate to 1 or 0, instead of
types.
What are the pros and cons of the different approaches? Does it help
much with compilation times especially overload resolution?
|
I don't think it matters too much with compile times, as long as the
computations are linear. I have gotten into trouble with compile time
calculations of greater complexity
(http://www.cuj.com/documents/s=8248/cujcexp2104dewhurst/) and there
the use of constants would save some measurable time.
| Quote: | In particular, consider the following type-based dispatch:
template <typename T> void perform (T t, __true_type)
{
// code that is only valid if discriminate <T>::type is __true_type
}
template <typename T> void perform (T t, __false_type)
{
// code that is only valid if discriminate <T>::type is __false_type
}
template <typename T> void perform (T t)
{
perform (t, typename discriminate <T>::type ());
}
|
When I have a choice, I prefer to use partial specialization:
template <typename T, bool>
struct Perform {
static void perform( T ) {
// code that is only valid if discriminate <T>::r is true
}
};
template <typename T>
struct Perform<T,false> {
static void perform( T ) {
// code that is only valid if discriminate <T>::r is false
}
};
template <typename T> void perform (T t) {
Perform<T,discriminate::perform (t);
}
I prefer this because a) it saves me from the nagging doubt that
passing a trivial argument at runtime to achieve a compile time result
actually will have a measurable runtime cost, and b) partial
specialization permits finer-grain control over the type arguments (no
stripping of reference modifiers or type-qualifiers). It's also
generally simpler than dealing with function template resolution,
easier to extend to multiway branches, etc. I tend to use function
templates primarily (but not exclusively) for argument deduction and
to provide a nice interface to the user of a facility.
| Quote: | Because the code in perform (T, __true_type) is only valid if
discriminate <T>::type is true, you can't use the neater formulation:
template <typename T> void perform (T t)
{
if (discriminate <T>::value)
// code that is only valid if discriminate <T>::value is true
else
// code that is only valid if discriminate <T>::value is false
}
Instead it seems you have to resort to a clumsy dispatch over an
external class structure and specialization which essentially mimics
the type-based approach, but only has the minor advantage of not
invoking overload resolution. Is there any neat way to achieve a
single function like the above?
|
Not that I know of.
Steve
Steve Dewhurst
www.semantics.org
[ 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
|
Posted: Tue Mar 02, 2004 8:52 pm Post subject: Re: Compile-time dispatch using types vs. constant integral |
|
|
[email]glenlow (AT) pixelglow (DOT) com[/email] (Glen Low) writes:
| Quote: | The old SGI STL (still living in gcc) had a lot of code partially
specialized on __true_type and __false_type
From what you show below, you're talking about overloading, not
partial specialization. |
| Quote: | and then had code that dispatched to the correct specialization
|
overload
| Quote: | based on some compile-time info e.g. trivial constructor. In
cpp_type_traits.h in libstdc++, Gabriel Dos Reis (and I think boost)
|
Boost doesn't have anything to say about libstdc++
| Quote: | advocates dispatch based on constant integral expressions that
evaluate to 1 or 0, instead of types.
|
I think you're misreading Gaby's comments. He's saying that to access
the results of his traits (such as __is_integer<T>), you access a
nested member of the trait template that is a value and not a type.
Now, the fact that he called the member "_M_type" and not something
with the word "value" in it is IMO heinous, but since these are GCC
internals and not meant for public consumption, it shouldn't really
matter to the rest of us.
Boost's type traits, in fact, work differently. As a convenience
they all contain a nested static bool ::value, but they also contain
a nested ::type. Usually they're built this way:
template <bool Value>
struct bool_
{
static bool const value = Value;
typedef bool_<Value> type;
};
typedef bool_<true> true_;
typedef bool_<false> false_;
template <class T>
some_trait
: // either true_ or false_
{
};
As a result, you can dispatch this way:
some_algorithm(whatever, some_trait<T>())
where there are two some_algorithm overloads on true_ and false_.
| Quote: | What are the pros and cons of the different approaches? Does it help
much with compilation times especially overload resolution?
|
That really depends on the compiler. GCC never been very fast at
compiling template code, and AFAICT has become a lot slower recently.
I would imagine, however, that when you don't run into the problem you
describe below, almost any compiler will be faster at compiling an if
statement than it will be at overload resolution, provided the two
clauses of the if aren't too huge. How significant that is, though,
is really implementation-dependent.
| Quote: | In particular, consider the following type-based dispatch:
template <typename T> void perform (T t, __true_type)
{
// code that is only valid if discriminate <T>::type is __true_type
}
template <typename T> void perform (T t, __false_type)
{
// code that is only valid if discriminate <T>::type is __false_type
}
template <typename T> void perform (T t)
{
perform (t, typename discriminate <T>::type ());
}
Because the code in perform (T, __true_type) is only valid if
discriminate <T>::type is true, you can't use the neater formulation:
template <typename T> void perform (T t)
{
if (discriminate <T>::value)
// code that is only valid if discriminate <T>::value is true
else
// code that is only valid if discriminate <T>::value is false
}
Instead it seems you have to resort to a clumsy dispatch over an
external class structure and specialization which essentially mimics
the type-based approach, but only has the minor advantage of not
invoking overload resolution.
|
This is a classic trade-off between expressiveness and (compile-time)
efficiency.
| Quote: | Is there any neat way to achieve a single function like the above?
|
If I understand your question correctly, then no. The whole body of a
function template is instantiated at once, and it must *all* be
well-formed C++ code in order for the function template to compile.
Cheers,
--
Dave Abrahams
Boost Consulting
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 |
|
 |
Gabriel Dos Reis Guest
|
Posted: Tue Mar 02, 2004 8:54 pm Post subject: Re: Compile-time dispatch using types vs. constant integral |
|
|
[email]glenlow (AT) pixelglow (DOT) com[/email] (Glen Low) writes:
| Quote: | The old SGI STL (still living in gcc) had a lot of code partially
specialized on __true_type and __false_type, and then had code that
dispatched to the correct specialization based on some compile-time
info e.g. trivial constructor. In cpp_type_traits.h in libstdc++,
Gabriel Dos Reis (and I think boost) advocates dispatch based on
constant integral expressions that evaluate to 1 or 0, instead of
types.
|
[...]
| Quote: | Because the code in perform (T, __true_type) is only valid if
discriminate <T>::type is true, you can't use the neater formulation:
template <typename T> void perform (T t)
{
if (discriminate <T>::value)
// code that is only valid if discriminate <T>::value is true
else
// code that is only valid if discriminate <T>::value is false
}
Instead it seems you have to resort to a clumsy dispatch over an
external class structure and specialization which essentially mimics
the type-based approach, but only has the minor advantage of not
invoking overload resolution. Is there any neat way to achieve a
single function like the above?
|
I don't quite understand what you're reporting here. Did you
// <from the file you quote>
See valarray_array.h for a case use.
?
--
Gabriel Dos Reis
[email]gdr (AT) cs (DOT) tamu.edu[/email]
Texas A&M University -- Computer Science Department
301, Bright Building -- College Station, TX 77843-3112
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Gabriel Dos Reis Guest
|
Posted: Tue Mar 02, 2004 8:55 pm Post subject: Re: Compile-time dispatch using types vs. constant integral |
|
|
"Stephen C. Dewhurst" <scd (AT) semantics (DOT) org> writes:
| Quote: | On 2 Mar 2004 06:32:39 -0500, [email]glenlow (AT) pixelglow (DOT) com[/email] (Glen Low) wrote:
The old SGI STL (still living in gcc) had a lot of code partially
specialized on __true_type and __false_type, and then had code that
dispatched to the correct specialization based on some compile-time
info e.g. trivial constructor. In cpp_type_traits.h in libstdc++,
Gabriel Dos Reis (and I think boost) advocates dispatch based on
constant integral expressions that evaluate to 1 or 0, instead of
types.
What are the pros and cons of the different approaches? Does it help
much with compilation times especially overload resolution?
|
[...]
| Quote: | When I have a choice, I prefer to use partial specialization:
|
That is what I recommend as primary choice, for the reasons you gave
later on. I'm quite puzzled by what Glen Low is reporting here.
| Quote: | template <typename T, bool
struct Perform {
static void perform( T ) {
// code that is only valid if discriminate
}
};
template <typename T
struct Perform
static void perform( T ) {
// code that is only valid if discriminate <T>::r is false
}
};
template <typename T> void perform (T t) {
Perform<T,discriminate::perform (t);
}
|
Did Glen Low follow the suggestion made in the file he was quoting,
namely
See valarray_array.h for a case use.
he would have read many situations like the ones you give above.
--
Gabriel Dos Reis
[email]gdr (AT) cs (DOT) tamu.edu[/email]
Texas A&M University -- Computer Science Department
301, Bright Building -- College Station, TX 77843-3112
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Antoun Kanawati Guest
|
Posted: Tue Mar 02, 2004 8:55 pm Post subject: Re: Compile-time dispatch using types vs. constant integral |
|
|
As far as specialization within template argument lists, the two
approaches are essentially interchangeable:
template<typename blah> struct get_value;
template<> struct get_value<__true_type>
{ enum { value = 1 } };
template<> struct get_value<__false_type>
{ enum { value = 0 } };
template<int n> struct get_type { typedef __true_type type; };
template<> struct get_type<0> { typedef __false_type type; };
However, compile-time constants provide no resolution when they
appear in function argument lists, thereby forcing resolution
by conditional branching, as you have shown below.
Whereas compile-time resolution of type-based overloads is
known to happen at compile time, even with all optimizations
off, resolution by conditional branching may or may not be
performed at compile time (depends on optimization level and
compiler implementation).
The other disadvantage of branch-based behavior is that it
adds references to the possible branches within the same
vicinity/translation-unit, which has implications on linkage
requirements, and precludes site-specific specializations.
Finally, when meta-programming, types-as-constants can be made to
carry payloads (accessible directly with Type::Property), whereas
integral values require extra template indirection. So, generally
speaking, type-constants (such as true_type/false_type) are more
convenient.
Glen Low wrote:
| Quote: | The old SGI STL (still living in gcc) had a lot of code partially
specialized on __true_type and __false_type, and then had code that
dispatched to the correct specialization based on some compile-time
info e.g. trivial constructor. In cpp_type_traits.h in libstdc++,
Gabriel Dos Reis (and I think boost) advocates dispatch based on
constant integral expressions that evaluate to 1 or 0, instead of
types.
What are the pros and cons of the different approaches? Does it help
much with compilation times especially overload resolution?
In particular, consider the following type-based dispatch:
template <typename T> void perform (T t, __true_type)
{
// code that is only valid if discriminate <T>::type is __true_type
}
template <typename T> void perform (T t, __false_type)
{
// code that is only valid if discriminate <T>::type is __false_type
}
template <typename T> void perform (T t)
{
perform (t, typename discriminate <T>::type ());
}
Because the code in perform (T, __true_type) is only valid if
discriminate <T>::type is true, you can't use the neater formulation:
template <typename T> void perform (T t)
{
if (discriminate <T>::value)
// code that is only valid if discriminate <T>::value is true
else
// code that is only valid if discriminate <T>::value is false
}
Instead it seems you have to resort to a clumsy dispatch over an
external class structure and specialization which essentially mimics
the type-based approach, but only has the minor advantage of not
invoking overload resolution. Is there any neat way to achieve a
single function like the above?
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
|
Posted: Wed Mar 03, 2004 11:48 am Post subject: Re: Compile-time dispatch using types vs. constant integral |
|
|
| Quote: | When I have a choice, I prefer to use partial specialization:
template <typename T, bool
struct Perform {
static void perform( T ) {
// code that is only valid if discriminate
}
};
template <typename T
struct Perform
static void perform( T ) {
// code that is only valid if discriminate <T>::r is false
}
};
template <typename T> void perform (T t) {
Perform<T,discriminate::perform (t);
}
I prefer this because a) it saves me from the nagging doubt that
passing a trivial argument at runtime to achieve a compile time result
actually will have a measurable runtime cost, and b) partial
specialization permits finer-grain control over the type arguments (no
stripping of reference modifiers or type-qualifiers). It's also
generally simpler than dealing with function template resolution,
easier to extend to multiway branches, etc. I tend to use function
templates primarily (but not exclusively) for argument deduction and
to provide a nice interface to the user of a facility.
|
Hmmm... you still get those advantages with a type-based solution e.g.
template <typename T, typename some_kind_of_truth>
struct Perform {
static void perform( T ) {
// code that is only valid if discriminate <T>::type is
__true_type
}
};
template <typename T>
struct Perform<T,__false_type> {
static void perform( T ) {
// code that is only valid if discriminate <T>::type is
__false_type
}
};
template <typename T> void perform (T t) {
Perform<T,typename discriminate::perform (t);
}
I still think though it looks slightly more obscure than the original
overloaded-on-type solution: (A) it's not evident that __true_type or
true is handled by the unspecialized template, unless you further
muddy the waters by declaring the template and define only the
specialized versions, (B) it introduces an auxilliary class and its
public member into the namespace scope, instead of just another
function overload.
It also still splits up the code pertaining to each branch, which was
my issue with the overload-on-type.
Now if only we could partially specialize a local class (which we
could put inside of the perform free function) or partially specialize
a free function...
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 |
|
 |
Stephen C. Dewhurst Guest
|
Posted: Wed Mar 03, 2004 11:48 am Post subject: Re: Compile-time dispatch using types vs. constant integral |
|
|
On 2 Mar 2004 15:55:56 -0500, Antoun Kanawati <antounk (AT) comcast (DOT) net>
wrote:
| Quote: | Finally, when meta-programming, types-as-constants can be made to
carry payloads (accessible directly with Type::Property), whereas
integral values require extra template indirection. So, generally
speaking, type-constants (such as true_type/false_type) are more
convenient.
|
Yes and no. Your point sounds quite reasonable, so I had a look at my
own metatprogramming code of the last year or so, and I tend not to
"payload" a type-as-constant with additional information. Now let me
try to justify why I don't.
It seems to me that, in general, any information I would embed in such
a type would be derived from the parameters to the primary template or
user interface function. Often, this information is more easily and
clearly obtained from a partial specialization of the primary
template. (The let-the-compiler-do-the-work model of information
collection.)
In other cases, I prefer to make the "branch" decision based on an
integral constant or the equivilent, un-payloaded type and extract the
information on an ad hoc basis in a more local context (by "local
context" I mean the class template partial or full specialization or
overloaded function to which we "branch").
I believe this is often a better approach for two reasons. First, in
a local context, we know more precisely what information is required,
and are able to better extract that information using ad hoc methods
within the local context. (In other words, it's OK do do weird,
expedient stuff in a private local context.) Second, by keeping this
information extraction as local as possible, we can minimize the
problems that accompany trying to decide what information a
"payloaded" type should carry to satisfy all the potential local
contexts. Of course, that could mean some duplication of code to
extract the same information in different local contexts, but in my
experience the overall reduction in complexity is worth the price of
any duplication.
Steve
Steve Dewhurst
www.semantics.org
[ 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
|
Posted: Wed Mar 03, 2004 11:51 am Post subject: Re: Compile-time dispatch using types vs. constant integral |
|
|
| Quote: | | Because the code in perform (T, __true_type) is only valid if
| discriminate <T>::type is true, you can't use the neater formulation:
|
| template <typename T> void perform (T t)
| {
| if (discriminate <T>::value)
| // code that is only valid if discriminate <T>::value is true
| else
| // code that is only valid if discriminate <T>::value is false
| }
|
| Instead it seems you have to resort to a clumsy dispatch over an
| external class structure and specialization which essentially mimics
| the type-based approach, but only has the minor advantage of not
| invoking overload resolution. Is there any neat way to achieve a
| single function like the above?
I don't quite understand what you're reporting here. Did you
//
See valarray_array.h for a case use.
|
I did look at valarray_array.h -- after all, macstl does independently
implement valarray -- but I took issue with the slightly clumsier need
to define an auxiliary class, public member functions and
specializations just to get what you would get with overloads in the
first place. See my reply to Steve, if it makes it through the mod.
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
|
Posted: Wed Mar 03, 2004 8:23 pm Post subject: Re: Compile-time dispatch using types vs. constant integral |
|
|
"Stephen C. Dewhurst" <scd (AT) semantics (DOT) org> writes:
| Quote: | Finally, when meta-programming, types-as-constants can be made to
carry payloads (accessible directly with Type::Property), whereas
integral values require extra template indirection. So, generally
speaking, type-constants (such as true_type/false_type) are more
convenient.
Yes and no. Your point sounds quite reasonable, so I had a look at my
own metatprogramming code of the last year or so, and I tend not to
"payload" a type-as-constant with additional information. Now let me
try to justify why I don't.
It seems to me that, in general, any information I would embed in such
a type would be derived from the parameters to the primary template or
user interface function. Often, this information is more easily and
clearly obtained from a partial specialization of the primary
template. (The let-the-compiler-do-the-work model of information
collection.)
|
The problem with specializations (and overloads) is that they reduce
encapsulation and spread information about the functionality of a
given template (or function) around the source code. From a
comprehensibility point-of-view, it's better to avoid them when
possible.
I should also point out that there's a really good reason for the
Boost convention of using types everywhere: it increases polymorphism
and interoperability. Consider the appearance of wrappers such as
int2type in metaprograms we've seen in the past.
When you really start to put thought into creating a template
metaprogramming framework you find out that types have to be the
common way of representing metadata, and that raising them to
first-class status (rather than treating them as mere ugly
neccessities) can make metaprograms much more expressive, and even
more efficient.
Consider:
template <class T> struct fu {};
template <class U> struct bar{ enum { value = 1 }; };
template <class V> struct baz
{
enum { value = bar<V>::value || fu<V>::value };
};
int x[baz<int>::value];
fu above is intentionally missing a ::value in order to demonstrate
that fu<V> is instantiated despite the short-circuit nature of
operator||.
Now compare with:
#include <boost/mpl/or.hpp>
template <class T> struct fu {};
template <class U> struct bar{ enum { value = 1 }; };
template <class V>
struct baz
: mpl::or_<bar
{};
int x[baz<int>::value];
which exhibits the desired short-circuit behavior, *and* is less
verbose than the other formulation above.
--
Dave Abrahams
Boost Consulting
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 |
|
 |
Gabriel Dos Reis Guest
|
Posted: Wed Mar 03, 2004 8:44 pm Post subject: Re: Compile-time dispatch using types vs. constant integral |
|
|
[email]glenlow (AT) pixelglow (DOT) com[/email] (Glen Low) writes:
| Quote: | I don't quite understand what you're reporting here. Did you
//
See valarray_array.h for a case use.
I did look at valarray_array.h
|
So, you probably saw that it uses partial specializations, and at
sometimes, just a plain if(...) ... else ... that gets optimized by the
compiler.
| Quote: | -- after all, macstl does independently implement valarray
|
the fact that macstl indenpendently implement valarray is logically
independent of having seen valarray_array.h or not. Sorry.
The reason I asked was that you seem to be confused and make reports
that are at antipode of what is going on.
Actually, I was not expecting someone would produce an implementation
of valarray by looking at valarray_*.h or taking issues with partial
specializations used there.
--
Gabriel Dos Reis
[email]gdr (AT) cs (DOT) tamu.edu[/email]
Texas A&M University -- Computer Science Department
301, Bright Building -- College Station, TX 77843-3112
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Gabriel Dos Reis Guest
|
Posted: Wed Mar 03, 2004 8:45 pm Post subject: Re: Compile-time dispatch using types vs. constant integral |
|
|
David Abrahams <dave (AT) boost-consulting (DOT) com> writes:
| Quote: | advocates dispatch based on constant integral expressions that
evaluate to 1 or 0, instead of types.
I think you're misreading Gaby's comments. He's saying that to access
the results of his traits (such as __is_integer<T>), you access a
nested member of the trait template that is a value and not a type.
|
Definitely right.
| Quote: | Now, the fact that he called the member "_M_type" and not something
with the word "value" in it is IMO heinous, but since these are GCC
internals and not meant for public consumption, it shouldn't really
matter to the rest of us.
|
[and I'm amazed tehd ebated was accepted i the first place ]
That file was put deep into a directory whose name clearly indicates
that it was internal business; furtheremore thingies in that file were
moglified to indicate that they weren't supposed to be of interest to
outsiders. Still, someone figured out a way to get to it and make a
public debate about it, that is funny :-)
Well, why not "value"? I could not remember whether "value" was a
reserved identifier. So arguably, I could have choosen "_M_value" or
"_S_value" or "_Whatever_value", but I doubt it could have been less
heinous.
[...]
| Quote: | What are the pros and cons of the different approaches? Does it help
much with compilation times especially overload resolution?
That really depends on the compiler. GCC never been very fast at
compiling template code, and AFAICT has become a lot slower recently.
|
At the time I wrote that file, four years ago,
(1) I really wanted to use a constant expression (not just a type) in
a code; (something like
if(__is_xxx<T>::_M_type && __is_yyy<T>::_M_type) blah else blah).
I knew the compiler I was writing the code against
optimizes things like if(0) or if(1) after syntax checking.
(2) I also wanted to use partial specialization to control the
codepath;
(3) thee compiler was consuming lots of resources and was slow
(surprise: it did not get better last time I checked).
That component was not written against arbitrary compilers.
I estimate that the reasons that pushed me to write that file (and the
starting comments at the request of a fellow maintainer) still apply
today. Eventually, they will get standard names, either through the
traits proposal or through the concept work (if it was accepted).
--
Gabriel Dos Reis
[email]gdr (AT) cs (DOT) tamu.edu[/email]
Texas A&M University -- Computer Science Department
301, Bright Building -- College Station, TX 77843-3112
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Gabriel Dos Reis Guest
|
Posted: Wed Mar 03, 2004 8:49 pm Post subject: Re: Compile-time dispatch using types vs. constant integral |
|
|
Antoun Kanawati <antounk (AT) comcast (DOT) net> writes:
| Quote: | Whereas compile-time resolution of type-based overloads is
known to happen at compile time, even with all optimizations
off, resolution by conditional branching may or may not be
performed at compile time (depends on optimization level and
compiler implementation).
|
I knew, when I wrote that file 4 years ago, that the compiler I was
writing the component for optimizes as it should if(0) or if(1). The
choice was not made lightly. And to clear any confusion (contrary to
what Glen Low is spreading here) I did not write the branches so that
they would refuse to compile.
That was 4 years ago. If a contemporary compilier can't remove codes
known unreachable (e.g. part of if(0)) when it is optimizing, then
it already has serious problems; that is independent of using a
constant or a type as I used.
I have met some people who did not know they have to tell the compiler
that it can optimize (e.g. -O flags), but I have not yet met people
using GCC in production code who did not turn optimizations on.
Maybe I'm too lucky so far.
--
Gabriel Dos Reis
[email]gdr (AT) cs (DOT) tamu.edu[/email]
Texas A&M University -- Computer Science Department
301, Bright Building -- College Station, TX 77843-3112
[ 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
|
Posted: Thu Mar 04, 2004 1:08 pm Post subject: Re: Compile-time dispatch using types vs. constant integral |
|
|
Gabriel Dos Reis <gdr (AT) cs (DOT) tamu.edu> writes:
| Quote: | Antoun Kanawati <antounk (AT) comcast (DOT) net> writes:
| Whereas compile-time resolution of type-based overloads is
| known to happen at compile time, even with all optimizations
| off, resolution by conditional branching may or may not be
| performed at compile time (depends on optimization level and
| compiler implementation).
I knew, when I wrote that file 4 years ago, that the compiler I was
writing the component for optimizes as it should if(0) or if(1). The
choice was not made lightly. And to clear any confusion (contrary to
what Glen Low is spreading here) I did not write the branches so that
they would refuse to compile.
That was 4 years ago. If a contemporary compilier can't remove codes
known unreachable (e.g. part of if(0)) when it is optimizing, then
it already has serious problems; that is independent of using a
constant or a type as I used.
|
True, but some will warn of constant expressions in conditionals, and
if you're trying to write code that induces no warnings (as some
people must), that technique may not apply.
--
Dave Abrahams
Boost Consulting
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 |
|
 |
Stephen C. Dewhurst Guest
|
Posted: Thu Mar 04, 2004 1:32 pm Post subject: Re: Compile-time dispatch using types vs. constant integral |
|
|
On 3 Mar 2004 15:23:31 -0500, David Abrahams
<dave (AT) boost-consulting (DOT) com> wrote:
| Quote: | When you really start to put thought into creating a template
metaprogramming framework you find out that types have to be the
common way of representing metadata, and that raising them to
first-class status (rather than treating them as mere ugly
neccessities) can make metaprograms much more expressive, and even
more efficient.
|
Actually, I don't see types as ugly necessities, but as interesting
organisms to be dissected and reassembled closer to the heart's
desire. But that's another topic...
| Quote: | Consider:
snip
fu above is intentionally missing a ::value in order to demonstrate
that fu<V> is instantiated despite the short-circuit nature of
operator||.
Now compare with:
snip
which exhibits the desired short-circuit behavior, *and* is less
verbose than the other formulation above.
|
Well, now you've got me since I'm not sufficiently familiar with Boost
to point out that the complexity is still there, it's just been moved
into a library (which is, of course, a good thing if it's done
properly). I'll review the Boost source and get back to you with
where you've gone wrong.
Steve
Steve Dewhurst
www.semantics.org
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
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
|
|