Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Curiously recurring template pattern

Reply
Thread Tools

Curiously recurring template pattern

 
 
Rob Williscroft
Guest
Posts: n/a
 
      07-10-2004
Alf P. Steinbach wrote in news: in
comp.lang.c++:

>> What about export makes you think it won't work ?

>
> The reason I'm wondering was given in the next paragraph, cited below:
>
>
>> > Okay I don't have a compiler that supports 'export' so don't know
>> > much about it, but if it's able to compile templates separately
>> > then it seems that the _linker_ must detect the invalid
>> > static_cast.

>>
>> The "compilation" done by export is only half the "compilation" that
>> needs to be done. A compiler that implements export must do the
>> second half (instantiation) at _link_ time.

>
> By studying your answers below I think I see what's going on. It's
> not instantiation at _link_ time but instantiation that uses
> precompiled information. In other words, the compiler needs access to
> the compiled form of the template, not just the header file -- and
> if that's the case then 'export' seems to be a very limited feature.
>


Yes, I think it promises faster compile times, and also the exported
code that isn't in a header (the defenition's) gets protected from
#include order and #define issues, though both of these might affect
the specialization's found and overloads found by ADL.

> The alternative is that the linker invokes a partial compilation, or
> at least class hierarchy information, but below you answer "no" to
> that?
>


Well it can "precompile" any bits that are non-dependant, say:

// "exported.hpp"
export template < typename T > struct X
{
int foo();
T bar();
};

// EOF

// "exported.cpp"
#include "exported.hpp"
#include <string>
using namespace std;

int X< T >::foo()
{
return 1;
}

template < typename T >
T X< T >::bar()
{
return T( foo(), string( "bar" ) );
}

X< T >::foo() could be fully compiled, but X< T >::bar() would
need to be in some itermediate form.

However the call's to X< T >::foo() and
std::string::string( char const * ) would be fully resolved and fixed.

Also std::basic_string< char > (aka std::string) could be instantiated
(unless its also exported).

// "main.cpp"

#include <string>
struct string
{
string( char const * ) {}
};

struct Y
{
int ii;
std::string ss;
Y( int i, std::string s ) : ii( i ), ss( s ) {}
};

#include "exported.hpp"

int main()
{
X< Y > x( 0, "" );
X< Y > y( x.bar() );
}

AFAICT the compilation of "main.cpp" would have to export the
declaration's and defenition's of Y<>, so that the linker/compiler
could actually instantiate X< Y >.

Or maybe when compiling "main.cpp" the compiler would /import/
whatever was exported by compiling "exported.cpp":

14/9 [Note: an implementation may require that a translation
unit containing the definition of an exported template be compiled
before any translation unit containing an instantiation of that
template. ]

The more I type (into this post) the more I'm becoming convinced
that any compilation-speedups export might give us ara a *fragile*
thing at best .

>
>> > So, is that detection required by the standard (if so, where), and
>> > are linkers really that smart?

>>
>> No the compiler (whenever it compiles) detects the errors:
>>
>> When the compiler instantiates the exported code it need's to
>> callback (if you like) to the main compile to get all the info' about
>> the paramiter types.

>
>


Rob. -- http://www.victim-prime.dsl.pipex.com/
 
Reply With Quote
 
 
 
 
Jonathan Turkanis
Guest
Posts: n/a
 
      07-10-2004

"Alf P. Steinbach" <> wrote in message
news:...
> * Jonathan Turkanis:
> >
> > "Alf P. Steinbach" <> wrote in message
> > news:...
> > > * iuweriur:
> > > > A few questions on the curiously recurring template pattern:
> > > >
> > > > This page:
> > > > http://c2.com/cgi/wiki?CuriouslyRecurringTemplate
> > > >
> > > > this part:
> > > > template<typename T> struct ArithmeticType
> > > > {
> > > > T operator + (const T& other) const
> > > > {
> > > > T result(*this); // <--------- THIS LINE
> > > > result += other;
> > > > return result;
> > > > }
> > > > // etc.
> > > > };


> > A static_cast should do the trick here.

>
> Keeping in mind that no cast is needed if the scheme shown in my

earlier
> posting is used: no, the reason I wrote dynamic_cast, not

static_cast, is
> that the (presumed) constructor is public, and so cannot know what

kind of
> beast it's passed. Of course ArithmeticType then needs at least one
> virtual function.


I understand. But dynamic_cast should not be required with CRTP, which
is supposed to be as efficient as if the code from the base were
hand-written in the derived class.

I often write a function self() in the base class which returns *this
cast to the derived type.

Jonathan


 
Reply With Quote
 
 
 
 
Alf P. Steinbach
Guest
Posts: n/a
 
      07-11-2004
* Jonathan Turkanis:
>
> "Alf P. Steinbach" <> wrote in message
> news:...
> > * Jonathan Turkanis:
> > >
> > > "Alf P. Steinbach" <> wrote in message
> > > news:...
> > > > * iuweriur:
> > > > > A few questions on the curiously recurring template pattern:
> > > > >
> > > > > This page:
> > > > > http://c2.com/cgi/wiki?CuriouslyRecurringTemplate
> > > > >
> > > > > this part:
> > > > > template<typename T> struct ArithmeticType
> > > > > {
> > > > > T operator + (const T& other) const
> > > > > {
> > > > > T result(*this); // <--------- THIS LINE
> > > > > result += other;
> > > > > return result;
> > > > > }
> > > > > // etc.
> > > > > };

>
> > > A static_cast should do the trick here.

> >
> > Keeping in mind that no cast is needed if the scheme shown in my

> earlier
> > posting is used: no, the reason I wrote dynamic_cast, not

> static_cast, is
> > that the (presumed) constructor is public, and so cannot know what

> kind of
> > beast it's passed. Of course ArithmeticType then needs at least one
> > virtual function.

>
> I understand. But dynamic_cast should not be required with CRTP, which
> is supposed to be as efficient as if the code from the base were
> hand-written in the derived class.
>
> I often write a function self() in the base class which returns *this
> cast to the derived type.


Well the point may be academic (whether to use pure virtual self() or
non-virtual inline self() with static_cast is personal preference ++),
but I think for completeness it should be noted that static_cast is
not 100% type-safe here. I.e., it does not _guarantee_ a compilation
error in case of incorrect usage. At least not with VC 7.1, which, by
means of threats of giving it some heavy template code, I succeded in
getting to accept the following code which is incorrect as can be:


#include <iostream>

template<typename T>
class ArithmeticType
{
public:
T operator+ (const T& other) const
{
T result( *static_cast<T const*>( this ) );
result += other;
return result;
}
// etc.
};

class Fraction: public ArithmeticType<Fraction>
{
private:
int x, y; // Represents x/y.
public:
Fraction(): x( 1234 ), y( 9999 ) {}
Fraction& operator+=( Fraction const& other )
{
// Whatever.
int something = x + y;
return *this;
}
};

struct UnboundedInt {};

// This ingenious new class provides _unbounded_ precision fractions!
class Fractionn: public ArithmeticType<Fraction>
{
private:
UnboundedInt x, y; // Represents x/y.
public:

Fractionn() {}
Fractionn( Fraction const& ) {} // Conversion Fraction to Fractionn
operator Fraction() const { return Fraction(); } // Other way.

Fractionn& operator+=( Fractionn const& other )
{
// Whatever.
return *this;
}
};

int main()
{
Fractionn a, b;
Fractionn c = a + b;
}

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
Jonathan Turkanis
Guest
Posts: n/a
 
      07-11-2004

"Alf P. Steinbach" <> wrote in message
news:...
> * Jonathan Turkanis:
> >
> > "Alf P. Steinbach" <> wrote in message
> > news:...
> > > * Jonathan Turkanis:
> > > >
> > > > "Alf P. Steinbach" <> wrote in message


> > > > A static_cast should do the trick here.
> > >
> > > Keeping in mind that no cast is needed if the scheme shown in my

> > earlier
> > > posting is used: no, the reason I wrote dynamic_cast, not

> > static_cast, is
> > > that the (presumed) constructor is public, and so cannot know

what
> > kind of
> > > beast it's passed. Of course ArithmeticType then needs at least

one
> > > virtual function.

> >
> > I understand. But dynamic_cast should not be required with CRTP,

which
> > is supposed to be as efficient as if the code from the base were
> > hand-written in the derived class.
> >
> > I often write a function self() in the base class which returns

*this
> > cast to the derived type.

>
> Well the point may be academic (whether to use pure virtual self()

or
> non-virtual inline self() with static_cast is personal preference

++),

I disagree. Using virtual functions could make the base class unusable
for many applications. Take Boost.Operators, for example
(http://www.boost.org/libs/utility/operators.htm), which uses CRTP for
exactly the same purpose as the OP's example. If Boost.Operators used
virtual functions instead of static_casts it would be useless for
defining numeric types such as Boost.Rational, where performance is
paramount.

Of course, for windows and buttons it probably makes no difference.

> but I think for completeness it should be noted that static_cast is
> not 100% type-safe here. I.e., it does not _guarantee_ a

compilation
> error in case of incorrect usage.


True. Unfortunately, I don't think static_asserts work in this case.
Therefore, where performance is important, we'll have to settle for
documentation which states, for example, that

struct X : ArithmeticType<Y> { };

is an error if X != Y.

Jonathan


 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      07-11-2004
* Jonathan Turkanis:
>
> >
> > Well the point may be academic (whether to use pure virtual self()
> > or non-virtual inline self() with static_cast is personal preference
> > ++),

>
> I disagree. Using virtual functions could make the base class unusable
> for many applications. Take Boost.Operators, for example
> (http://www.boost.org/libs/utility/operators.htm), which uses CRTP for
> exactly the same purpose as the OP's example. If Boost.Operators used
> virtual functions instead of static_casts it would be useless for
> defining numeric types such as Boost.Rational, where performance is
> paramount.


That's in the "++". In some cases performance means using unsafe
features. On the other hand, boost::lexical_cast goes to the opposite
extreme end to provide type-safety by sacrificing performance, so clearly
there is preference involved in many cases...

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
Jonathan Turkanis
Guest
Posts: n/a
 
      07-12-2004

"Alf P. Steinbach" <> wrote in message
news:...
> * Jonathan Turkanis:
> >
> > >
> > > Well the point may be academic (whether to use pure virtual

self()
> > > or non-virtual inline self() with static_cast is personal

preference
> > > ++),

> >
> > I disagree. Using virtual functions could make the base class

unusable
> > for many applications. Take Boost.Operators, for example
> > (http://www.boost.org/libs/utility/operators.htm), which uses CRTP

for
> > exactly the same purpose as the OP's example. If Boost.Operators

used
> > virtual functions instead of static_casts it would be useless for
> > defining numeric types such as Boost.Rational, where performance

is
> > paramount.

>
> That's in the "++".


I guess I don't know what that means.

> In some cases performance means using unsafe
> features. On the other hand, boost::lexical_cast goes to the

opposite
> extreme end to provide type-safety by sacrificing performance, so

clearly
> there is preference involved in many cases...


I'm certainly not going to argue that you should never give up
performance for saftey. I've just never considered CRTP an unsafe
idiom.

Jonathan


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Curiously Recurring Template Pattern chsalvia@gmail.com C++ 4 07-11-2007 01:22 PM
A class scope allocator using the Curiously Recursive Template Pattern AndrewD C++ 4 01-26-2007 11:32 PM
Curiously Recurring Template Problem Martin MacRobert C++ 4 07-26-2004 10:46 PM
curiously recurring template pattern problem Denis Remezov C++ 7 04-07-2004 10:50 AM
Curiously recursive pattern-what is that??? papi1976 C++ 5 02-05-2004 06:55 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57