By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,908 Members | 1,271 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,908 IT Pros & Developers. It's quick & easy.

Named Constructor idiom - a question

P: n/a
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 different
constructors by their first parameter:

struct Type1 {};
struct Type2 {};

class Foo
{
public:
Foo( Type1, int x );
Foo( Type2, int y );
};

Foo a = Foo( Type1(), 10 );
Foo b = Foo( Type2(), 10 );

My solution was to use enums to differentiate them:

enum Type1 { eType1 };
enum Type2 { eType2 };

class Foo
{
public:
Foo( Type1, int x );
Foo( Type2, int y );
};

Foo a = Foo( eType1, 10 );
Foo b = Foo( eType2, 10 );
Are there any advantages or disadvantages to either method?
I guess the enums take up storage space, but so do the empty structs right?

Enums need 2 identifiers - the type name and the value, whereas the struct
only needs one identifier?

Enums don't need a () to construct them.
I'm not convinced either way (yet!). Indeed, is another method?

Does anyone have any views?
--
Regards,
Steve

"What if the Hokey Cokey really IS what it's all about?"

Jul 23 '05 #1
Share this Question
Share on Google+
10 Replies


P: n/a
Steve wrote:
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 different
constructors by their first parameter:

struct Type1 {};
struct Type2 {};

class Foo
{
public:
Foo( Type1, int x );
Foo( Type2, int y );
};

Foo a = Foo( Type1(), 10 );
Foo b = Foo( Type2(), 10 );
Why not simply

Foo a(Type1(), 10);
Foo b(Type2(), 10);

???
My solution was to use enums to differentiate them:

enum Type1 { eType1 };
enum Type2 { eType2 };

class Foo
{
public:
Foo( Type1, int x );
Foo( Type2, int y );
};

Foo a = Foo( eType1, 10 );
Foo b = Foo( eType2, 10 );
Again, you don't need the '='...
Are there any advantages or disadvantages to either method?
No difference, AFAICS.
I guess the enums take up storage space, but so do the empty structs right?
Right.
Enums need 2 identifiers - the type name and the value, whereas the struct
only needs one identifier?
No, they don't. You can use the enums like you did structs:

Foo a(Type1(), 10);

Since enum Type1 is a separate type, and you're not using the actual value
of it in your constructor, Type1() is just constructing an temporary of
the enum Type1 type, and gives it value 0.
Enums don't need a () to construct them.
Unless you use the enumeration (type) name.
I'm not convinced either way (yet!). Indeed, is another method?

Does anyone have any views?


You can make a template constructors:

class Type1 {};
class Type2 {};

class Foo {
public:
template<class T> Foo(T,int) {
// implement the default behaviour
}
};

template<> Foo::Foo<Type1>(Type1, int i) {
// implement the first one
}

template<> Foo::Foo<Type2>(Type2, int i) {
// implement the other one
}

int main() {
Foo a(Type1(), 10);
Foo b(Type2(), 10);
Foo ab(int(), 10);
}

I am not sure what the advantage might be... The only thing I can
think of at the moment is that if you construct from some third type,
you will end up using the "default" specialisation, from the class
definition... Not much, I guess :-)

V
Jul 23 '05 #2

P: n/a
On 22/7/05 23:03, in article
P2******************@newsread1.mlpsca01.us.to.veri o.net, "Victor Bazarov"
<v.********@comAcast.net> wrote:
Foo a = Foo( Type1(), 10 );
Foo b = Foo( Type2(), 10 );
Why not simply

Foo a(Type1(), 10);
Foo b(Type2(), 10);

???


Ummm, yes, errr... well spotted... ;-)
Enums need 2 identifiers - the type name and the value, whereas the struct
only needs one identifier?


No, they don't. You can use the enums like you did structs:

Foo a(Type1(), 10);

Since enum Type1 is a separate type, and you're not using the actual value
of it in your constructor, Type1() is just constructing an temporary of
the enum Type1 type, and gives it value 0.
Enums don't need a () to construct them.


Unless you use the enumeration (type) name.


[sound of light switch...] Ah, yes, of course - just like int(), etc.
You can make a template constructors:
[snipped example code]
I am not sure what the advantage might be... The only thing I can
think of at the moment is that if you construct from some third type,
you will end up using the "default" specialisation, from the class
definition... Not much, I guess :-)


I would say thatıs less safe, since I want to make sure only those
constructors I specify can be used.
Thanks very much your input, Victor. At least I know now I'm not going
wildly off track!

--
Regards,
Steve

"What if the Hokey Cokey really IS what it's all about?"

Jul 23 '05 #3

P: n/a
>

I guess the enums take up storage space, but so do the empty structs
right?


Actually I don't think either solution will take up any space at all.
Definitions of data types (structs, enums) don't take up any space, as this
information is only used at compile time.

You don't allocate anything, except temporary instances of empty structs,
which take up as much space as an ordinary pointer = 4 bytes on 32 bit
systems.

Using your enum solution will just convert the enums to integer constants
which also take up 4 bytes on a 32 bit system - again, the type information
is only used at compile time to link to the right function.

Either way you get what you want, and everything is resolved at compile time
so it doesn't take up any runtime resources :o)

The best,
Mogens
Jul 23 '05 #4

P: n/a
On 23/7/05 08:58, in article 42**********************@nntp02.dk.telia.net,
"Mogens Heller Jensen" <mo****@mookid.dk> wrote:


I guess the enums take up storage space, but so do the empty structs
right?


Actually I don't think either solution will take up any space at all.
Definitions of data types (structs, enums) don't take up any space, as this
information is only used at compile time.

You don't allocate anything, except temporary instances of empty structs,
which take up as much space as an ordinary pointer = 4 bytes on 32 bit
systems.

Using your enum solution will just convert the enums to integer constants
which also take up 4 bytes on a 32 bit system - again, the type information
is only used at compile time to link to the right function.

Either way you get what you want, and everything is resolved at compile time
so it doesn't take up any runtime resources :o)

You've just contradicted yourself?! First you say they don't take up space,
then you say they use 4 bytes?

There must be storage *somewhere* because I could take the address of struct
or enum?

--
Regards,
Steve

"What if the Hokey Cokey really IS what it's all about?"

Jul 23 '05 #5

P: n/a
Steve wrote:
I'm not convinced either way (yet!). Indeed, is another method?


Yes, the one you mention in your headline but not in your post:
A named constructor. What you posted is not a named constructor but a
normal constructor feeded with a tag-type. I think a better, less
confusing approach would be this:

class Foo {
private:
Foo(int x) { /* ... */ }
public:
static Foo type1(int x) {
/* construct and return type1 Foo */
}
static Foo type2(int x) {
/* construct and return type2 Foo */
}
};

See http://www.parashift.com/c++-faq-lit....html#faq-10.8 for a more
comprehensive example of how to use this idiom.

--
Matthias Kaeppler
Jul 23 '05 #6

P: n/a
On 23/7/05 11:15, in article db*************@news.t-online.com, "Matthias
Kaeppler" <no****@digitalraid.com> wrote:
Steve wrote:
I'm not convinced either way (yet!). Indeed, is another method?


Yes, the one you mention in your headline but not in your post:
A named constructor. What you posted is not a named constructor but a
normal constructor feeded with a tag-type. I think a better, less
confusing approach would be this:

class Foo {
private:
Foo(int x) { /* ... */ }
public:
static Foo type1(int x) {
/* construct and return type1 Foo */
}
static Foo type2(int x) {
/* construct and return type2 Foo */
}
};

See http://www.parashift.com/c++-faq-lit....html#faq-10.8 for a more
comprehensive example of how to use this idiom.

I did consider that, but the objects I'm really constructing in my
application are non-copyable. (I posted a simplified example!).
--
Regards,
Steve

"What if the Hokey Cokey really IS what it's all about?"

Jul 23 '05 #7

P: n/a
Steve wrote:
I did consider that, but the objects I'm really constructing in my
application are non-copyable. (I posted a simplified example!).


So they're non-copyable (must have missed that). And how does that
relate to the named ctor idiom? No copy construction is involved, just
usual constructor calls.

--
Matthias Kaeppler
Jul 23 '05 #8

P: n/a
* Matthias Kaeppler:
Steve wrote:
I did consider that, but the objects I'm really constructing in my
application are non-copyable. (I posted a simplified example!).


So they're non-copyable (must have missed that). And how does that
relate to the named ctor idiom? No copy construction is involved, just
usual constructor calls.


In order to directly be a function result type the type needs to be
copyable, even if the copy constructor call is optimized away in practice
(as it usually is). If the type is not copyable dynamic allocation is
required. So it's a question of efficiency and convenience.

--
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 23 '05 #9

P: n/a

"Steve" <ro**@127.0.0.1> wrote in message
news:BF07BC52.EB752%ro**@127.0.0.1...
On 23/7/05 08:58, in article 42**********************@nntp02.dk.telia.net,
"Mogens Heller Jensen" <mo****@mookid.dk> wrote:


I guess the enums take up storage space, but so do the empty structs
right?


Actually I don't think either solution will take up any space at all.
Definitions of data types (structs, enums) don't take up any space, as
this
information is only used at compile time.

You don't allocate anything, except temporary instances of empty structs,
which take up as much space as an ordinary pointer = 4 bytes on 32 bit
systems.

Using your enum solution will just convert the enums to integer constants
which also take up 4 bytes on a 32 bit system - again, the type
information
is only used at compile time to link to the right function.

Either way you get what you want, and everything is resolved at compile
time
so it doesn't take up any runtime resources :o)

You've just contradicted yourself?! First you say they don't take up
space,
then you say they use 4 bytes?

There must be storage *somewhere* because I could take the address of
struct
or enum?


Oh yeah, I seem to have had some trouble explaining myself... what I meant
was that _definitions of datatypes_, be it classes, structs or enums, do not
take up any space, as they are merely information for the compiler to use
during compilation.

If you instantiate something, it will of course take up some space - so if
you instantiate e.g. a struct (by passing it as a temporary), of course
there will be a pointer somewhere.

But in this case it will not take up any more space than the pointer itself,
since the struct is empty, which amounts to 2 x sizeof(structpointer)

Enums are just treated as constants by the compiler, so again: it will take
up space if you instantiate them. So if no instances exist, the only space
used will be the constants deducted from them - in this case 2 x
sizeof(int).

Hope this clears it.

The best,
Mogens
Jul 23 '05 #10

P: n/a
Alf P. Steinbach wrote:
In order to directly be a function result type the type needs to be
copyable, even if the copy constructor call is optimized away in practice
(as it usually is). If the type is not copyable dynamic allocation is
required. So it's a question of efficiency and convenience.


Point taken.

--
Matthias Kaeppler
Jul 23 '05 #11

This discussion thread is closed

Replies have been disabled for this discussion.