473,396 Members | 1,775 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Curiously recurring template pattern

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.
};

In the above marked line, how comes that one doesn't need any type of
cast from *this to const T& ?

And if the cast is needed, what type of cast would you use?
I suppose that the reinterpret_cast would not be portable (in theory, or
also in practice?) and anyway does not handle cases with MI, and the
dynamic_cast is slow and works only on polimorphic types, right?


Another question on this page:
http://www.informit.com/articles/art...31473&seqNum=3

At the end there is written:
----
In general, CRTP is useful to factor out implementations of interfaces
that can only be member functions (for example, constructor,
destructors, and subscript operators).
----

For the subscript I can maybe understand, but how can you do it for
constructors and destructors?
Thank you
iuweriur

Jul 22 '05 #1
15 3053
* 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.
};

In the above marked line, how comes that one doesn't need any type of
cast from *this to const T& ?
Presumably the intent is that class T has a public constructor that takes
an ArithmeticType<T> argument and uses dynamic_cast down to T.

I think that's ugly, and doing a downcast in ArithmeticType is also ugly.

Downcasting is what virtual functions are all about achieving in a type-
safe and efficient manner, so I'd write
template<typename T>
class ArithmeticType
{
protected:
virtual T const& thisT() const = 0;

T operator + (const T& other) const
{
T result( thisT() );
result += other;
return result;
}
// etc.
};
And if the cast is needed, what type of cast would you use?
No cast needed; see above.

Another question on this page:
http://www.informit.com/articles/art...31473&seqNum=3

At the end there is written:
----
In general, CRTP is useful to factor out implementations of interfaces
that can only be member functions (for example, constructor,
destructors, and subscript operators).
----

For the subscript I can maybe understand, but how can you do it for
constructors and destructors?


A set of classes may have very similar constructors or constructor parts,
differing only in the concrete types involved.

Such a constructor can be factored out in a CRT base class.

For example, the CRT base class might be Window, and a typical derived
class Button, and Button might have a static function nativeWindowHandle()
that the Window class constructor calls; see FAQ 23.4 for other techniques
to do just about the same without using the CRT pattern.

--
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?
Jul 22 '05 #2

"Alf P. Steinbach" <al***@start.no> wrote in message
news:40**************@news.individual.net...
* 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.
};

In the above marked line, how comes that one doesn't need any type of cast from *this to const T& ?
Presumably the intent is that class T has a public constructor that

takes an ArithmeticType<T> argument and uses dynamic_cast down to T.


A static_cast should do the trick here. I think it's required in the
above example. Maybe the authors were using VC6.

Jonathan
Jul 22 '05 #3

"Jonathan Turkanis" <te******@kangaroologic.com> wrote in message
news:2l************@uni-berlin.de...
A static_cast should do the trick here. I think it's required in the
above example. Maybe the authors were using VC6.


Whoops. VC6 needs the cast too.


Jul 22 '05 #4
* Jonathan Turkanis:

"Alf P. Steinbach" <al***@start.no> wrote in message
news:40**************@news.individual.net...
* 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.
};

In the above marked line, how comes that one doesn't need any type of cast from *this to const T& ?


Presumably the intent is that class T has a public constructor that

takes
an ArithmeticType<T> argument and uses dynamic_cast down to T.


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.

--
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?
Jul 22 '05 #5
Jonathan Turkanis wrote:
A static_cast should do the trick here. I think it's required in the
above example. Maybe the authors were using VC6.

Jonathan

Hey how can you use static_cast to downcast like this?
When the compiler compiles the ArithmeticType, *this is not guaranteed
to be of type T as far as the compiler knows

Am I wrong?
Jul 22 '05 #6
On Sat, 10 Jul 2004 03:50:56 -0500, iuweriur <iu******@hhhh.com> wrote:
Jonathan Turkanis wrote:
A static_cast should do the trick here. I think it's required in the
above example. Maybe the authors were using VC6.
Jonathan

Hey how can you use static_cast to downcast like this?
When the compiler compiles the ArithmeticType, *this is not guaranteed
to be of type T as far as the compiler knows

Am I wrong?


Isn't that the whole point of static_cast?

If the CRTP is being used correctly *this will be as base class of type T
and the static_cast will work. If CRTP is being used incorrectly then
*this will not be a base class of T and you will get a compile error.

john
Jul 22 '05 #7
* John Harrison:
On Sat, 10 Jul 2004 03:50:56 -0500, iuweriur <iu******@hhhh.com> wrote:
Jonathan Turkanis wrote:
A static_cast should do the trick here. I think it's required in the
above example. Maybe the authors were using VC6.
Jonathan

Hey how can you use static_cast to downcast like this?
When the compiler compiles the ArithmeticType, *this is not guaranteed
to be of type T as far as the compiler knows

Am I wrong?


Isn't that the whole point of static_cast?

If the CRTP is being used correctly *this will be as base class of type T
and the static_cast will work. If CRTP is being used incorrectly then
*this will not be a base class of T and you will get a compile error.


Well I'm wondering about that: how does it work with 'export'? <g/>

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.

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

--
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?
Jul 22 '05 #8
Alf P. Steinbach wrote in news:40***************@news.individual.net in
comp.lang.c++:
Isn't that the whole point of static_cast?

If the CRTP is being used correctly *this will be as base class of
type T and the static_cast will work. If CRTP is being used
incorrectly then *this will not be a base class of T and you will
get a compile error.
Well I'm wondering about that: how does it work with 'export'? <g/>


What about export makes you think it won't work ?
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.

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:

template < typename A, typename B >
A &my_cast( B &b )
{
return static_cast< A & >( b );
}

struct base {} b;
struct derived : base {} d;

int main()
{
base &b = d;
derived &d = my_cast< derived >( b );

int &i = my_cast< int >( d ); /* <-- error */
}

If my_cast<>() were exported then the export mechanism would need to
be told sufficient information about base and derived so that it could
be instantiated, and sufficient info' about derived so it knows it can't
do the static_cast< int & >, there is no difference between the exported
code calling static_cast<>, or operator + or trying to invoke A::foo().

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/
Jul 22 '05 #9
* Rob Williscroft:
Alf P. Steinbach wrote in news:40***************@news.individual.net in
comp.lang.c++:
Isn't that the whole point of static_cast?

If the CRTP is being used correctly *this will be as base class of
type T and the static_cast will work. If CRTP is being used
incorrectly then *this will not be a base class of T and you will
get a compile error.


Well I'm wondering about that: how does it work with 'export'? <g/>


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.

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

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.


--
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?
Jul 22 '05 #10
Alf P. Steinbach wrote in news:40***************@news.individual.net 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/
Jul 22 '05 #11

"Alf P. Steinbach" <al***@start.no> wrote in message
news:40***************@news.individual.net...
* Jonathan Turkanis:

"Alf P. Steinbach" <al***@start.no> wrote in message
news:40**************@news.individual.net...
* 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
Jul 22 '05 #12
* Jonathan Turkanis:

"Alf P. Steinbach" <al***@start.no> wrote in message
news:40***************@news.individual.net...
* Jonathan Turkanis:

"Alf P. Steinbach" <al***@start.no> wrote in message
news:40**************@news.individual.net...
> * 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?
Jul 22 '05 #13

"Alf P. Steinbach" <al***@start.no> wrote in message
news:40***************@news.individual.net...
* Jonathan Turkanis:

"Alf P. Steinbach" <al***@start.no> wrote in message
news:40***************@news.individual.net...
* Jonathan Turkanis:
>
> "Alf P. Steinbach" <al***@start.no> 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
Jul 22 '05 #14
* 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?
Jul 22 '05 #15

"Alf P. Steinbach" <al***@start.no> wrote in message
news:40****************@news.individual.net...
* 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
Jul 22 '05 #16

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: papi1976 | last post by:
Hello to everyone I heard about a strange thing about wich i have'nt find anything on the net or books, someone called this "Curiously recursive pattern" or a strange trick to play with...
14
by: John Harrison | last post by:
The following code does not compile template <class Derived> struct X { typedef typename Derived::type type; }; struct Y : public X<Y> {
4
by: Martin MacRobert | last post by:
Hi Gang, The following code does not compile, but I can't figure out why. The compiler complains that the CuriouslyDerivedType (CRDerived) does not publish the "value_type", yet in fact the class...
4
by: AndrewD | last post by:
Hey C++ folks, I created this today, just for fun. You can make object allocation for any class around 6 times faster, simply by doing the following. class MyClass : public...
4
by: chsalvia | last post by:
The "Curiously Recurring Template Pattern" (CRTP) recently caught my attention as a nice trick which allows static polymorphism. In other words, it lets you build extensible classes without the...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.