default contructing an object of unknown type T

A

Alf P. Steinbach /Usenet

* Hicham Mouline, on 30.07.2010 12:03:
Hello,

inside a template function, I need an instance of type T that is to be
default constructed.
I would normally write:

template<typename T>
void f(const T&) {
const T t();
}

This then requires T to have a default ctor, which is good.

However this doesn't work for primitive types where default ctor means
zeroing it.

Am I missing something obvious?

Like


template< class T >
struct DefaultConstructed
{
T v;

DefaultConstructed(): v() {}
};

I'm thinking of using type_traits

Hm.


Cheers & hth.,

- Alf
 
F

Francesco S. Carta

Francesco said:
"Keith H Duggar"<[email protected]>

I guess what I really want is 1) and 2), after detecting whether T is
fundamental or not.
T const& t = T() ;

I vaguely recall that even that requires access to the copy ctor, and
the
compiler is allowed to use it too, though most do not. (Even more
vaguely I recall an accident with MSVC version around 5.0 where copy was
actually used before binding the reference.)

Yeah, you are right. How odd.

Could someone point out some reference to this requirement? MinGW 4.4.0
allows the above statement even for T = [some type with copy constructor
declared private and not even defined] where that statement has no
access to the private interface of T.

If it is a requirement, the compiler should have refused the code I
posted in the other branch of this thread, but it compiled it just fine.

The clause is [8.5.3/5]:

A reference to type ?cv1 T1? is initialized by an expression of type ?cv2
T2? as follows:
- If the initializer expression
[non applicable clause]
- Otherwise, the reference shall be to a non-volatile const type (i.e.,
cv1 shall be const).
[example]
- If the initializer expression is an rvalue, with T2 a class type, and
?cv1 T1? is reference-compatible with ?cv2 T2,? the reference is bound
in one of the following ways (the choice is implementation-defined):
- The reference is bound to the object represented by the rvalue (see
3.10) or to a sub-object within that object.
- A temporary of type ?cv1 T2? [sic] is created, and a constructor is
called to copy the entire rvalue object into the temporary. The
reference is bound to the temporary or to a sub-object within the
temporary.
The constructor that would be used to make the copy shall be callable
whether or not the copy is actually done.
- Otherwise [non applicable clause]


Thank you for reporting the reference, please read below.
No, it's not an extension. Also, g++ on linux rejects the following code:


class dummy {

dummy ( dummy const& ) {}

public:

dummy ( void ) {}

};

int main ( void ) {
dummy x = dummy();
}


If the windows version accepts the code, it would be a bug.

No, it rejects it as expected. Could you please check if the Linux
version compiles the code I posted in my other follow-ups?

I'm not sure if the compiler is free to ignore the following:

"The constructor that would be used to make the copy shall be callable
whether or not the copy is actually done."

because it seems to be free to implement direct binding to the first
temporary:

"The reference is bound to the object represented by the rvalue"

(assuming I got it straight).

In any case, seems clear that the suggested change to the OP:

const T& t = T();

Is implementation defined and thus non-portable at least.
 
F

Francesco S. Carta

on said:
* Hicham Mouline, on 30.07.2010 12:03:

Like


template< class T >
struct DefaultConstructed
{
T v;

DefaultConstructed(): v() {}
};

I've also tried something like that, but stomped on the fact that the OP
wants a const object within the template function.

If you try to combine your class with the OP's template I think you'll
stomp on the same problem (trying to allow non-copy-constructible types,
of course, because that requirement has been added afterwards).

If you succeed, please post the solution here. My best shot is:

{
T* pt = new T;
{
const T& t = *pt;
// use t
}
delete pt;
}
 
K

Kai-Uwe Bux

Francesco said:
Francesco said:
"Keith H Duggar"<[email protected]>

I guess what I really want is 1) and 2), after detecting whether T
is fundamental or not.
T const& t = T() ;

I vaguely recall that even that requires access to the copy ctor, and
the
compiler is allowed to use it too, though most do not. (Even more
vaguely I recall an accident with MSVC version around 5.0 where copy
was actually used before binding the reference.)

Yeah, you are right. How odd.

Could someone point out some reference to this requirement? MinGW 4.4.0
allows the above statement even for T = [some type with copy constructor
declared private and not even defined] where that statement has no
access to the private interface of T.

If it is a requirement, the compiler should have refused the code I
posted in the other branch of this thread, but it compiled it just fine.

The clause is [8.5.3/5]:

A reference to type ?cv1 T1? is initialized by an expression of type
?cv2 T2? as follows:
- If the initializer expression
[non applicable clause]
- Otherwise, the reference shall be to a non-volatile const type
(i.e.,
cv1 shall be const).
[example]
- If the initializer expression is an rvalue, with T2 a class type,
and
?cv1 T1? is reference-compatible with ?cv2 T2,? the reference is
bound in one of the following ways (the choice is
implementation-defined): - The reference is bound to the object
represented by the rvalue (see
3.10) or to a sub-object within that object.
- A temporary of type ?cv1 T2? [sic] is created, and a constructor
is
called to copy the entire rvalue object into the temporary. The
reference is bound to the temporary or to a sub-object within
the temporary.
The constructor that would be used to make the copy shall be
callable whether or not the copy is actually done.
- Otherwise [non applicable clause]


Thank you for reporting the reference, please read below.
No, it's not an extension. Also, g++ on linux rejects the following code:


class dummy {

dummy ( dummy const& ) {}

public:

dummy ( void ) {}

};

int main ( void ) {
dummy x = dummy();
}


If the windows version accepts the code, it would be a bug.

No, it rejects it as expected. Could you please check if the Linux
version compiles the code I posted in my other follow-ups?

I'm not sure if the compiler is free to ignore the following:

"The constructor that would be used to make the copy shall be callable
whether or not the copy is actually done."

No, it is not. The operative word is "shall".
because it seems to be free to implement direct binding to the first
temporary:

"The reference is bound to the object represented by the rvalue"

(assuming I got it straight).

In any case, seems clear that the suggested change to the OP:

const T& t = T();

Is implementation defined and thus non-portable at least.

No, it's not implementation defined. It will work with C++0X but is illegal
as of now for types T with disabled copy constructor. G++ is buggy in this
regard (and I screwed up the test case). It does compile but should reject
the following:

class dummy {

dummy ( dummy const & );

public:

dummy ( void ) {}

};

int main ( void ) {
const dummy & x = dummy();
}

Interesting to note: g++-4.2.3 rejects the code (with an error message
pointing out that the copy constructors is private) but g++-4.3.1 accepts
the code. Maybe, this is not so much a bug but a move toward C++0x.


Best

Kai-Uwe Bux
 
A

Alf P. Steinbach /Usenet

* Francesco S. Carta, on 30.07.2010 21:48:
I've also tried something like that, but stomped on the fact that the OP
wants a const object within the template function.

If you try to combine your class with the OP's template I think you'll
stomp on the same problem (trying to allow non-copy-constructible types,
of course, because that requirement has been added afterwards).

If you succeed, please post the solution here. My best shot is:

{
T* pt = new T;
{
const T& t = *pt;
// use t
}
delete pt;
}

I'm unable to see the problem that you allude to, but OK:


<code>
#include <iostream>
using namespace std;

template< class Type >
struct DefaultConstructed
{
Type v;
DefaultConstructed(): v() {}
};

template< class Type >
void f( Type const& )
{
DefaultConstructed< Type > const t;

cout << t.v << endl;
}


int main()
{
f( 42 );
}
</code>


Cheers & hth.,

- Alf
 
F

Francesco S. Carta

on said:
* Francesco S. Carta, on 30.07.2010 21:48:

I'm unable to see the problem that you allude to, but OK:


<code>
#include <iostream>
using namespace std;

template< class Type >
struct DefaultConstructed
{
Type v;
DefaultConstructed(): v() {}
};

template< class Type >
void f( Type const& )
{
DefaultConstructed< Type > const t;

cout << t.v << endl;
}


int main()
{
f( 42 );
}
</code>

The problem was just in my mind, since I've passed through references,
heading for the solution, when I've built a template class equivalent to
yours, I've unsuccessfully tried to create a const reference to it and I
simply discarded that solution without further investigation... silly me.

The solution to Hicham question is the one you just posted.
 
F

Francesco S. Carta

Francesco said:
Francesco S. Carta wrote:


"Keith H Duggar"<[email protected]>

I guess what I really want is 1) and 2), after detecting whether T
is fundamental or not.
T const& t = T() ;

I vaguely recall that even that requires access to the copy ctor, and
the
compiler is allowed to use it too, though most do not. (Even more
vaguely I recall an accident with MSVC version around 5.0 where copy
was actually used before binding the reference.)

Yeah, you are right. How odd.

Could someone point out some reference to this requirement? MinGW 4.4.0
allows the above statement even for T = [some type with copy constructor
declared private and not even defined] where that statement has no
access to the private interface of T.

If it is a requirement, the compiler should have refused the code I
posted in the other branch of this thread, but it compiled it just fine.

The clause is [8.5.3/5]:

A reference to type ?cv1 T1? is initialized by an expression of type
?cv2 T2? as follows:
- If the initializer expression
[non applicable clause]
- Otherwise, the reference shall be to a non-volatile const type
(i.e.,
cv1 shall be const).
[example]
- If the initializer expression is an rvalue, with T2 a class type,
and
?cv1 T1? is reference-compatible with ?cv2 T2,? the reference is
bound in one of the following ways (the choice is
implementation-defined): - The reference is bound to the object
represented by the rvalue (see
3.10) or to a sub-object within that object.
- A temporary of type ?cv1 T2? [sic] is created, and a constructor
is
called to copy the entire rvalue object into the temporary. The
reference is bound to the temporary or to a sub-object within
the temporary.
The constructor that would be used to make the copy shall be
callable whether or not the copy is actually done.
- Otherwise [non applicable clause]


Thank you for reporting the reference, please read below.
Is it yet another GCC extension? In case, is it a compliant one, for
what you can tell?

No, it's not an extension. Also, g++ on linux rejects the following code:


class dummy {

dummy ( dummy const& ) {}

public:

dummy ( void ) {}

};

int main ( void ) {
dummy x = dummy();
}


If the windows version accepts the code, it would be a bug.

No, it rejects it as expected. Could you please check if the Linux
version compiles the code I posted in my other follow-ups?

I'm not sure if the compiler is free to ignore the following:

"The constructor that would be used to make the copy shall be callable
whether or not the copy is actually done."

No, it is not. The operative word is "shall".
because it seems to be free to implement direct binding to the first
temporary:

"The reference is bound to the object represented by the rvalue"

(assuming I got it straight).

In any case, seems clear that the suggested change to the OP:

const T& t = T();

Is implementation defined and thus non-portable at least.

No, it's not implementation defined. It will work with C++0X but is illegal
as of now for types T with disabled copy constructor. G++ is buggy in this
regard (and I screwed up the test case). It does compile but should reject
the following:

class dummy {

dummy ( dummy const& );

public:

dummy ( void ) {}

};

int main ( void ) {
const dummy& x = dummy();
}

Interesting to note: g++-4.2.3 rejects the code (with an error message
pointing out that the copy constructors is private) but g++-4.3.1 accepts
the code. Maybe, this is not so much a bug but a move toward C++0x.

All the above clears out everything for me (setting apart the last note
that leaves the doubt to me too).

Thanks a lot for the details Kai.

Alf just came with the solution to the OP question. Silly me, I was
there a couple of hours ago and I wasn't able to see it... experience,
it makes a lot of difference.
 
J

Juha Nieminen

Francesco S. Carta said:
If you succeed, please post the solution here. My best shot is:

{
T* pt = new T;
{
const T& t = *pt;
// use t
}
delete pt;
}

That's horribly inefficient (besides not being exception-safe). Please
don't do it like that.
 
F

Francesco S. Carta

That's horribly inefficient (besides not being exception-safe). Please
don't do it like that.

Yes, I know, that's a monstrosity I have come up with trying to fully
satisfy the OP requirements.

Being efficient and exception safe was not part of the explicit
requirements ;-)

Luckily, Alf gave us a nice and fully working solution for the OP issue.
 
J

James Kanze

About your objection: every type has a copy constructor and an
assignment operator unless (for user created types) you forbid
its usage to the client code - even then, you're just
forbidding it, but the type still has a copy constructor and
an assignment operator (at least declared as private /
protected, if not defined && used somewhere by the internals).

No. At least not by what I would understand by "has".

In C++03, every type has a *declaration* of a copy constructor and
a copy assignment operator. But only a declaration. (And
depending on the contents of the class, the declaration might
take a non-const reference. In which case, I'm not sure that it
can be used in an expression like:
T value = T();
..) It doesn't have a definition (which is what I would
understand by "has") if the copy constructor is user declared,
and the user doesn't provide one, or if the type has a either a
non-static data member or a base of a type with an inaccessible
or ambiguous copy constructor. And the above expression
requires a copy constructor, not just a declaration.

In practice, of course, *most* types which don't support copy
aren't meant to be used as local variables anyway. (One major
exception is RAII classes, like mutex::lock.)
If you want to allow copy-forbidden and assignment-forbidden
classes into that template, you could make them to allow
default initialization using zero and use this line instead:
const T t(0);
this will ensure the compiler will not interpret it as a
function declaration, always allowing built-in types in.

But it will impose an additional constraint on user defined
types. Probably more constraining than supporting copy.
 
J

James Kanze

I believe they're considered synonymous and interchangeable
within the standard.

I can't find any mention of primitive types in the standard.
The fundamental types are defined in §3.9.1, and are char,
signed char, unsigned char, short, unsigned short, int, unsigned
int, long, unsigned long, bool, wchar_t, float, double, long
double and void. And no others. (In C++03. C++0x adds long
long, unsigned long long, and the possibility for an
implementation to add additional integral types.) Built-in
types include the fundamental types, plus arrays, pointers,
references, pointers to members, and maybe functions. (The
standard doesn't seem to actually define built-in types, but
most of the uses seem to concern operator overloading, where
built-in types seems to mean those for which you cannot overload
operators---e.g. everything but class and enum types.)
 
F

Francesco S. Carta

I can't find any mention of primitive types in the standard.
The fundamental types are defined in §3.9.1, and are char,
signed char, unsigned char, short, unsigned short, int, unsigned
int, long, unsigned long, bool, wchar_t, float, double, long
double and void. And no others. (In C++03. C++0x adds long
long, unsigned long long, and the possibility for an
implementation to add additional integral types.) Built-in
types include the fundamental types, plus arrays, pointers,
references, pointers to members, and maybe functions. (The
standard doesn't seem to actually define built-in types, but
most of the uses seem to concern operator overloading, where
built-in types seems to mean those for which you cannot overload
operators---e.g. everything but class and enum types.)

Heck, I believed the wrong thing... luckily I stopped arguing about the
standard and started putting my sentences in the "I believe", "I think"
form... my memory doesn't serve me very well in these cases ;-)

Thanks for your correction James.
 
F

Francesco S. Carta

No. At least not by what I would understand by "has".

In C++03, every type has a *declaration* of a copy constructor and
a copy assignment operator.

That was what I tried to express, I thought I somewhat clarified it with
the last parenthetical (the "at least declared as private / protected")
but actually it was far from a perfect description.
But only a declaration. (And
depending on the contents of the class, the declaration might
take a non-const reference. In which case, I'm not sure that it
can be used in an expression like:
T value = T();
.) It doesn't have a definition (which is what I would
understand by "has") if the copy constructor is user declared,
and the user doesn't provide one, or if the type has a either a
non-static data member or a base of a type with an inaccessible
or ambiguous copy constructor. And the above expression
requires a copy constructor, not just a declaration.

In practice, of course, *most* types which don't support copy
aren't meant to be used as local variables anyway. (One major
exception is RAII classes, like mutex::lock.)




But it will impose an additional constraint on user defined
types. Probably more constraining than supporting copy.

Yep, that was just a possible path for solving the OP's question, which
by now has been completely covered without having to add any constraint
on the used types.

Thank you for refining the first point above for me, James.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,226
Members
46,815
Latest member
treekmostly22

Latest Threads

Top