473,385 Members | 2,013 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,385 software developers and data experts.

Named CTORs - symualting it by tempaltes?



Hello,
this post is a big long so I made 3 sections

1. problem
2. code + compilation errors
3. idea for c++0x - new c++ standard? how about that...
=== 1 ================================================== =================

in some languages (like pascal, delphi) we can construct object using meany
functions with different names.

I would like to have something like this in C++.

To to do like:

class cRec {
cRec() { } // ctor
constructor CreateSimmilarTo(cRec &org) {}
constructor CreateRecordDeleting(cRec &org) {}
constructor CreateRecordUpdating(cRec &org, int timestamp) {}
};
and so on.

in c++ I can do it, as long if all CTORs differ by arguments, which is not
the case in c++/pascal like code above.

Of course I can work around it in meany ways, but no sollution is too nice.

class cRec {
cRec() { } // ctor
cRec(int action, cRec &org, int timestamp=0) {
if (action==1) { } // CreateSimmilarTo
else if (action==2) { } // CreateRecordDeleting
else if (action==3) { } // CreateRecordUpdating
}
};

it is not too nice, as it will not detect compile-time invalide combination
of action and following arguments like new cRec(1,123) or cRec(3);

=== 2 ================================================== =================

Therfore, my idea was to simulate it a bit by using templates, something
like:
cRec::cRec<0>(){}
cRec::cRec<1>(cRec &org){}
cRec::cRec<2>(cRec &org){}
cRec::cRec<3>(cRec &org, int timestamp){}

and usign it like:
cRec * x = new cRec<0>();
cRec * x = new cRec<2>(y);
cRec * x = new cRec<3>(y,time());

is that possible?

I tried something like:

--- code ---------------------------------------------------
template <int i> void bar() { } // this all works, as excercise
template <> void bar<0>() { } // ok
template <> void bar<1>() { } // ok
template <> void bar<2>() { } // ok

class cRec { // a record
template <int x> cRec(const char *a) {}
template <> cRec<0>(const char *a) {}
template <> cRec<1>(const char *a) {}
};

int main() {}
--- code ---------------------------------------------------

x.cpp:8: error: explicit specialization in non-namespace scope 'class cRec'
x.cpp:8: error: 'cRec' is not a template
x.cpp:8: error: expected unqualified-id before 'const'
x.cpp:8: error: expected `)' before 'const'
x.cpp:9: error: explicit specialization in non-namespace scope 'class cRec'
x.cpp:9: error: 'cRec' is not a template
x.cpp:9: error: expected unqualified-id before 'const'
x.cpp:9: error: expected `)' before 'const'

=== 3 ================================================== =================

Perhaps it would be a nice thing to have in C++ - name constructors?
It could reuse the keyword "new" to indicate that given function can be
called as constructor. It would change ABI / format of .o objects probably
to contain the additional information.

example of using would be:

cRec {
cRec() { } // normal, default ctor
cRec(int a) { } // normal ctor
cRec(int a, int b) { } // normal ctor overload
cRec(int a, std::vector<int> x) { } // normal ctor overload

// named constructors:
new FromTemplate(int x){} // use database record number X as template
new FromTemplate(const cRec &org){} // use record as template

// create from template, but ask user to customize it
new SimmilarTo(int x){}
new SimmilarTo(const cRec &org){}

// create from template, but use it as a record to delete existing one
new Deleting(int x){}
new Deleting(const cRec &org){}

// create from template, but use it as a record to supersede existing one
new Updating(int x){}
new Updating(const cRec &org){}
};

Of course it all could be done more manually, like by having empty default
constructor, and then calling some methods to finish creation, like
cRec *r = new cRec(100);
r->SetRole_Deleting();
but for more complicated cases it is far more elegant solution, in example
when immediatelly passing it to function
SendToDatabase( new cRec(100) .... )
have to be splited into:
cRec *r = new cRec(100);
r->SetRole_Deleting();
SendToDatabase(r);

In my extended c++ idea, the syntax would be elegant:
SendToDatabase(new cRec::Deleting(100));

Nowdays this also can be done, by a static method cRec::Deleting that would
be a factory function, creating and returning cRec*, but this is not too
elegant IMHO - what if we want to use something else then a new, like
placement new?

Any suggestions or opinions are wellcommed :)

--
Rafa³ Maj
May 31 '06 #1
7 1661
Raf256 wrote:
Hello,
this post is a big long so I made 3 sections

1. problem
2. code + compilation errors
3. idea for c++0x - new c++ standard? how about that...

in some languages (like pascal, delphi) we can construct object using meany
functions with different names.

I would like to have something like this in C++.

To to do like:

class cRec {
cRec() { } // ctor
constructor CreateSimmilarTo(cRec &org) {}
constructor CreateRecordDeleting(cRec &org) {}
constructor CreateRecordUpdating(cRec &org, int timestamp) {}
};
And how should these be used?
and so on.


How about static member functions?

class cRec
{
public:
// should that be a copy-ctor?
static cRec CreateSimilarTo(cRec& org);

static cRec CreateRecordDeleting(cRec& org);
static cRec CreateRecordUpdating(cRec& org, int timestamp);
};

void f(cRec& r)
{
cRec r1 = cRec::CreateRecordDeleting(r);
}

If copy construction is expensive (so that returning by value is not a
solution, even if NRVO may apply), use the pimpl idiom
(http://www.gotw.ca/gotw/024.htm). If the class cannot be changed, use
a proxy.

If that's not possible and initialization of members is not mandatory,
use a member or a friend function:

class cRec
{
public:
friend void CreateRecordDeleting(cRec& r);
};

void f()
{
cRec r;
CreateRecordDeleting(r);
}

If not, use static member functions to return a new-allocated object
wrapped in a smart pointer of some sort:

class cRec
{
public:
static std::auto_ptr<cRec> CreateRecordDeleting(cRec& org);
}

If not.. well I can't think of anything else right now.
Jonathan

May 31 '06 #2
Raf256 wrote:
=== 1
================================================== =================

in some languages (like pascal, delphi) we can construct object using
meany functions with different names.
We can use 'policies' in C++ for that. We also can use 'factory methods'.
I would like to have something like this in C++.

To to do like:

class cRec {
cRec() { } // ctor
constructor CreateSimmilarTo(cRec &org) {}
constructor CreateRecordDeleting(cRec &org) {}
constructor CreateRecordUpdating(cRec &org, int timestamp) {}
};
and so on.

in c++ I can do it, as long if all CTORs differ by arguments, which
is not the case in c++/pascal like code above.
Not the case? Out of three "constructors" you have two varieties of
the parameter list.
Of course I can work around it in meany ways, but no sollution is too
nice.
Nothing should be "too nice". Does it work? If yes, it'd good enough.
Making it "nice" for the sake of "niceness" is a waste of time. But I
digress...
class cRec {
cRec() { } // ctor
cRec(int action, cRec &org, int timestamp=0) {
if (action==1) { } // CreateSimmilarTo
else if (action==2) { } // CreateRecordDeleting
else if (action==3) { } // CreateRecordUpdating
}
};

it is not too nice, as it will not detect compile-time invalide
combination of action and following arguments like new cRec(1,123) or
cRec(3);

=== 2
================================================== =================

Therfore, my idea was to simulate it a bit by using templates,
something like:
cRec::cRec<0>(){}
cRec::cRec<1>(cRec &org){}
cRec::cRec<2>(cRec &org){}
cRec::cRec<3>(cRec &org, int timestamp){}

and usign it like:
cRec * x = new cRec<0>();
cRec * x = new cRec<2>(y);
cRec * x = new cRec<3>(y,time());

is that possible?
It is not possible to templatize constructors without providing a way
for the compiler to deduce the template argument[s]. What you can do
is provide derived class templates, which would cause createion of the
base class objects, but it's cumbersome.
I tried something like:

--- code ---------------------------------------------------
template <int i> void bar() { } // this all works, as excercise
template <> void bar<0>() { } // ok
template <> void bar<1>() { } // ok
template <> void bar<2>() { } // ok

class cRec { // a record
template <int x> cRec(const char *a) {}
template <> cRec<0>(const char *a) {}
template <> cRec<1>(const char *a) {}
This is not going to work. There is no way for the compiler to arrive
at '0' or '1' or any other number. The syntax simply doesn't exist.
And that's on top of the fact that member template specialisations are
not allowed in the class definition, IIRC.
};

int main() {}
--- code ---------------------------------------------------

x.cpp:8: error: explicit specialization in non-namespace scope 'class
cRec' x.cpp:8: error: 'cRec' is not a template
x.cpp:8: error: expected unqualified-id before 'const'
x.cpp:8: error: expected `)' before 'const'
x.cpp:9: error: explicit specialization in non-namespace scope 'class
cRec' x.cpp:9: error: 'cRec' is not a template
x.cpp:9: error: expected unqualified-id before 'const'
x.cpp:9: error: expected `)' before 'const'

=== 3
================================================== =================

Perhaps it would be a nice thing to have in C++ - name constructors?
Perhaps. But think of this: twenty years C++ managed without them. You
would need a really good reason and no work-arounds.
It could reuse the keyword "new" to indicate that given function can
be called as constructor. It would change ABI / format of .o objects
probably to contain the additional information.

example of using would be:

cRec {
cRec() { } // normal, default ctor
cRec(int a) { } // normal ctor
cRec(int a, int b) { } // normal ctor overload
cRec(int a, std::vector<int> x) { } // normal ctor overload

// named constructors:
new FromTemplate(int x){} // use database record number X as template
new FromTemplate(const cRec &org){} // use record as template

// create from template, but ask user to customize it
new SimmilarTo(int x){}
new SimmilarTo(const cRec &org){}

// create from template, but use it as a record to delete existing
one new Deleting(int x){}
new Deleting(const cRec &org){}

// create from template, but use it as a record to supersede
existing one new Updating(int x){}
new Updating(const cRec &org){}
};

Of course it all could be done more manually, like by having empty
default constructor, and then calling some methods to finish
creation, like cRec *r = new cRec(100);
r->SetRole_Deleting();
but for more complicated cases it is far more elegant solution, in
example when immediatelly passing it to function
SendToDatabase( new cRec(100) .... )
have to be splited into:
cRec *r = new cRec(100);
r->SetRole_Deleting();
SendToDatabase(r);

In my extended c++ idea, the syntax would be elegant:
SendToDatabase(new cRec::Deleting(100));

Nowdays this also can be done, by a static method cRec::Deleting that
would be a factory function, creating and returning cRec*, but this
is not too elegant IMHO - what if we want to use something else then
a new, like placement new?

Any suggestions or opinions are wellcommed :)


Read about "factory methods". If you only care about dynamic objects
(created using 'new'), you must be able to implement what you need
using those.

V
--
Please remove capital As from my address when replying by mail
Jun 1 '06 #3

"Raf256" <sp**@raf256.invalid> wrote in message
news:e5**********@inews.gazeta.pl...


Hello,
this post is a big long so I made 3 sections

1. problem
2. code + compilation errors
3. idea for c++0x - new c++ standard? how about that...
=== 1 ================================================== =================

in some languages (like pascal, delphi) we can construct object using
meany
functions with different names.

I would like to have something like this in C++.

To to do like:

class cRec {
cRec() { } // ctor
constructor CreateSimmilarTo(cRec &org) {}
constructor CreateRecordDeleting(cRec &org) {}
constructor CreateRecordUpdating(cRec &org, int timestamp) {}
};
and so on.

[snip]

What's wrong with using ordinary functions which return objects of the
desired type?

class cRec {
public:
cRec(...); // most general constructor -- probably with several
arguments
...
};

cRec CreateSimilarTo(cRec &org);
cRec CreateRecordDeleting(cRec &org);
cRec CreateRecordUpdating(cRec &org, int timestamp) ;

Then you use them as follows:

cRec x = CreateSimilarTo(org);

Cy
Jun 1 '06 #4

"Cy Edmunds" <sp***************@rochester.rr.com> wrote in message
news:X1******************@twister.nyroc.rr.com...

"Raf256" <sp**@raf256.invalid> wrote in message
news:e5**********@inews.gazeta.pl...


Hello,
this post is a big long so I made 3 sections

1. problem
2. code + compilation errors
3. idea for c++0x - new c++ standard? how about that...
=== 1 ================================================== =================

in some languages (like pascal, delphi) we can construct object using
meany
functions with different names.

I would like to have something like this in C++.

To to do like:

class cRec {
cRec() { } // ctor
constructor CreateSimmilarTo(cRec &org) {}
constructor CreateRecordDeleting(cRec &org) {}
constructor CreateRecordUpdating(cRec &org, int timestamp) {}
};
and so on.

[snip]

What's wrong with using ordinary functions which return objects of the
desired type?

class cRec {
public:
cRec(...); // most general constructor -- probably with several
arguments
...
};

cRec CreateSimilarTo(cRec &org);
cRec CreateRecordDeleting(cRec &org);
cRec CreateRecordUpdating(cRec &org, int timestamp) ;

Then you use them as follows:

cRec x = CreateSimilarTo(org);


Probably better to return a pointer, don't you think? Your method involves
construction of a temporary object, and copy-construction of the named (x)
object. (Of course, the compiler may be able to eliminate the extra step...
but maybe not.)

(Also, the org parameter should probably be a const reference.)

-Howard


Jun 1 '06 #5

"Howard" <al*****@hotmail.com> wrote in message
news:pE*********************@bgtnsc04-news.ops.worldnet.att.net...

"Cy Edmunds" <sp***************@rochester.rr.com> wrote in message
news:X1******************@twister.nyroc.rr.com...

"Raf256" <sp**@raf256.invalid> wrote in message
news:e5**********@inews.gazeta.pl...


Hello,
this post is a big long so I made 3 sections

1. problem
2. code + compilation errors
3. idea for c++0x - new c++ standard? how about that...
=== 1
================================================== =================

in some languages (like pascal, delphi) we can construct object using
meany
functions with different names.

I would like to have something like this in C++.

To to do like:

class cRec {
cRec() { } // ctor
constructor CreateSimmilarTo(cRec &org) {}
constructor CreateRecordDeleting(cRec &org) {}
constructor CreateRecordUpdating(cRec &org, int timestamp) {}
};
and so on.

[snip]

What's wrong with using ordinary functions which return objects of the
desired type?

class cRec {
public:
cRec(...); // most general constructor -- probably with several
arguments
...
};

cRec CreateSimilarTo(cRec &org);
cRec CreateRecordDeleting(cRec &org);
cRec CreateRecordUpdating(cRec &org, int timestamp) ;

Then you use them as follows:

cRec x = CreateSimilarTo(org);


Probably better to return a pointer, don't you think? Your method
involves construction of a temporary object, and copy-construction of the
named (x) object. (Of course, the compiler may be able to eliminate the
extra step... but maybe not.)

(Also, the org parameter should probably be a const reference.)

-Howard


I don't think it's better to return a pointer. As you say, the compiler
should remove any unnecessary copying. Returning an object allows me to use
the function to generate temporary objects as in:

t_transform x = translate(1, 3) * rotate(90);

This is an example from real life; transform and rotate return objects of
type t_transform which can then be operated on immediately. This is a lot
better than

std::auto_ptr<t_transform> p1 = translate(1, 3);
std::auto_ptr<t_transform> p2 = rotate(90);
t_transform x = (*p1) * (*p2);
p2.release();
p1.release();

Pointers at the interface often cause problems. For instance, is the client
supposed to delete the resulting pointer as the example shows? Just
returning the object is often a lot cleaner.

Cy
Jun 1 '06 #6

"Cy Edmunds" <sp***************@rochester.rr.com> wrote in message
news:mZ*****************@twister.nyroc.rr.com...



Probably better to return a pointer, don't you think? Your method
involves construction of a temporary object, and copy-construction of the
named (x) object. (Of course, the compiler may be able to eliminate the
extra step... but maybe not.)

(Also, the org parameter should probably be a const reference.)

-Howard


I don't think it's better to return a pointer. As you say, the compiler
should remove any unnecessary copying. Returning an object allows me to
use the function to generate temporary objects as in:

t_transform x = translate(1, 3) * rotate(90);

This is an example from real life; transform and rotate return objects of
type t_transform which can then be operated on immediately. This is a lot
better than

std::auto_ptr<t_transform> p1 = translate(1, 3);
std::auto_ptr<t_transform> p2 = rotate(90);
t_transform x = (*p1) * (*p2);
p2.release();
p1.release();

Pointers at the interface often cause problems. For instance, is the
client supposed to delete the resulting pointer as the example shows? Just
returning the object is often a lot cleaner.


Well, the original post showed the "constructors" being used with calls to
new, so I'd assume that what he wanted was a pointer.

Don't factories _usually_ return pointers (sometimes reference-counted) to
the created objects?

-Howard
Jun 1 '06 #7

"Howard" <al*****@hotmail.com> wrote in message
news:kE********************@bgtnsc05-news.ops.worldnet.att.net...

"Cy Edmunds" <sp***************@rochester.rr.com> wrote in message
news:mZ*****************@twister.nyroc.rr.com...


Probably better to return a pointer, don't you think? Your method
involves construction of a temporary object, and copy-construction of
the named (x) object. (Of course, the compiler may be able to eliminate
the extra step... but maybe not.)

(Also, the org parameter should probably be a const reference.)

-Howard


I don't think it's better to return a pointer. As you say, the compiler
should remove any unnecessary copying. Returning an object allows me to
use the function to generate temporary objects as in:

t_transform x = translate(1, 3) * rotate(90);

This is an example from real life; transform and rotate return objects of
type t_transform which can then be operated on immediately. This is a lot
better than

std::auto_ptr<t_transform> p1 = translate(1, 3);
std::auto_ptr<t_transform> p2 = rotate(90);
t_transform x = (*p1) * (*p2);
p2.release();
p1.release();

Pointers at the interface often cause problems. For instance, is the
client supposed to delete the resulting pointer as the example shows?
Just returning the object is often a lot cleaner.


Well, the original post showed the "constructors" being used with calls to
new, so I'd assume that what he wanted was a pointer.


Some people automatically use operator new whenever they want to create an
instance. I don't know why. Maybe the baneful influence of Java. :)

Anyway, if he specifically wants an object created by operator new, a
function which returns such a pointer is fine. Otherwise though it's a pain.

On the other hand, a function which returns an object can be used either
way:

t_transform t = rotate(90);
t_transform *p = new t_transform(rotate(90));

It can also be used with other forms of memory allocation if the situation
requires it.

Don't factories _usually_ return pointers (sometimes reference-counted) to
the created objects?
A function which simply returns a specific type of object doesn't really fit
the factory pattern.

-Howard

Jun 2 '06 #8

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

Similar topics

66
by: Darren Dale | last post by:
Hello, def test(data): i = ? This is the line I have trouble with if i==1: return data else: return data a,b,c,d = test()
3
by: Avin Patel | last post by:
Hi, I have one weakly named(i.e. not strong named) assembly/xyz.dll. And other strong named assemblies/.dll. I have found that I can't use weakly named assembly with strong named assembly. How...
0
by: Dave | last post by:
Hello all, 1. I am able to declare as explicit ctors that cannot take exactly one argument - they either take fewer (default ctor) or more arguments. What is the significance of declaring such...
4
by: Carsten Spieß | last post by:
Hello all, i have a problem with a template constructor I reduced my code to the following (compiled with gcc 2.7.2) to show my problem: // a base class class Base{}; // two derived...
6
by: BigMan | last post by:
Is it safe to call nonvirtual member functions from ctors and dtors? What about virtual ones?
10
by: Steve | last post by:
Hi, I thought I had invented a pretty neat solution for my problem, but it turns out I'm using the named constructor idiom. :-) I've seen examples where empty structs are used to identify the...
3
by: Adam Hartshorne | last post by:
What is named parameter mechanism? Any ideas? I am looking through some code and there is a comment saying "VC++ has trouble with the named parameters mechanism", which i have no idea what this...
14
by: cody | last post by:
I got a similar idea a couple of months ago, but now this one will require no change to the clr, is relatively easy to implement and would be a great addition to C# 3.0 :) so here we go.. To...
2
ADezii
by: ADezii | last post by:
When a call is made to a Sub or Function Procedure, you can supply Arguments in the exact order they appear in the Procedure's definition, or you can supply them in any position by name. To...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
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: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
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: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
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
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
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
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

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.