default contructing an object of unknown type T

H

Hicham Mouline

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?

I'm thinking of using type_traits

rds,
 
F

Francesco S. Carta

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?

Yes, you missed to test it, because it works just fine with every type
that can be default constructed - that includes built-in types.
 
F

Francesco S. Carta

Yes, you missed to test it, because it works just fine with every type
that can be default constructed - that includes built-in types.

Little addition: it works but it doesn't really achieve what you mean.

Due to the most vexing parse problem, the line:

const T t();

Will interpreted as a function declaration - it slipped past me as well.

What you want is:

const T t = T();
 
B

Balog Pal

Hicham Mouline said:
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();
}

IMO that would declare a function, so you actually need something like

const T t = T();
However this doesn't work for primitive types where default ctor means
zeroing it.

The default "ctor" does nothing, you need the explicit () form to have
value-init (zeroing).
Am I missing something obvious?

Probably yes, T() form works for anything, including built-in types.
 
H

Hicham Mouline

Francesco S. Carta said:
Little addition: it works but it doesn't really achieve what you mean.

Due to the most vexing parse problem, the line:

const T t();

Will interpreted as a function declaration - it slipped past me as well.

What you want is:

const T t = T();
But then that requires T to have a copy constructor, which it may not have.
 
J

Juha Nieminen

Hicham Mouline said:
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();
}

I think you mean: const T t = T();

What you wrote compiles (as written), but means something completely
different.
However this doesn't work for primitive types where default ctor means
zeroing it.

What do you mean that it doesn't work for primitive types?

Primitive types *do* have a default constructor, which is called with
the exact same syntax as with classes. This *is* valid:

int i = int();

They support that syntax precisely to make what you want work.
 
F

Francesco S. Carta

But then that requires T to have a copy constructor, which it may not have.

You need to change that line in any case, because it simply doesn't
instantiate an object, it declares a function.

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).

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.

I'm not so sure this is what you want, though, and as always - when
dealing with templates - you can take advantage of specializations.

If you post some example about the genre of classes you want to allow in
and which others to keep out (if any) you might get better help.
 
H

Hicham Mouline

Juha Nieminen said:
I think you mean: const T t = T();

What you wrote compiles (as written), but means something completely
different.


What do you mean that it doesn't work for primitive types?

Primitive types *do* have a default constructor, which is called with
the exact same syntax as with classes. This *is* valid:

int i = int();

They support that syntax precisely to make what you want work.

Thanks,

1) const T t;
works for user-defined types with a default contructor, but not for built-in
types.

2) const T t(0);
works for built-in types but assumes 0 is convertible to T and is equivalent
to default construction,
but doesn't work for user-defined types unless proper action is taken

3) const T t = T();
works for both user defined and built-in types but requires the T to have a
copy ctor.

I guess what I really want is 1) and 2), after detecting whether T is
fundamental or not.
type_traits allow to detect if T is fundamental

btw, the std mentions:
primitive
built-in
fundamental

can any type be 1 but not the other?

rds,
 
F

Francesco S. Carta

btw, the std mentions:
primitive
built-in
fundamental

can any type be 1 but not the other?

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

Francesco S. Carta

Thanks,

1) const T t;
works for user-defined types with a default contructor, but not for built-in
types.

2) const T t(0);
works for built-in types but assumes 0 is convertible to T and is equivalent
to default construction,
but doesn't work for user-defined types unless proper action is taken

3) const T t = T();
works for both user defined and built-in types but requires the T to have a
copy ctor.

I guess what I really want is 1) and 2), after detecting whether T is
fundamental or not.
type_traits allow to detect if T is fundamental

I think you don't need it, I've just realized you can use
sort-of-an-hack with const reference and a temporary, just write:

const T& t = T();

This should work fine even for types which are copy- and assign-
forbidden - modulo any misunderstanding of mine, but if I got it
straight, it's just not an hack and the temporary will live as long as
the const reference does:

//-------
#include <iostream>
#include <string>

using namespace std;

class NoCopyNoAssign {
public:
NoCopyNoAssign(string s = "[not specified]") : s(s) {}
friend ostream& operator<<(ostream& os, const NoCopyNoAssign& obj) {
os << obj.s;
return os;
}
private:
NoCopyNoAssign(const NoCopyNoAssign&);
NoCopyNoAssign& operator=(const NoCopyNoAssign&);
string s;
};

template<class T> void f(const T& passed) {
const T& local = T();
cout << "passed == " << passed << endl;
cout << "local == " << local << endl;
}

int main() {
NoCopyNoAssign ncna("initialized");
f(ncna);
int i = 42;
f(i);
}
//-------
 
K

Keith H Duggar

1) const T t;
works for user-defined types with a default contructor, but not for built-in
types.

2) const T t(0);
works for built-in types but assumes 0 is convertible to T and is equivalent
to default construction,
but doesn't work for user-defined types unless proper action is taken

3) const T t = T();
works for both user defined and built-in types but requires the T to have a
copy ctor.

I guess what I really want is 1) and 2), after detecting whether T is
fundamental or not.

T const & t = T() ;

KHD
 
J

Jonathan Lee

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.

Use static const T t. "static" causes zero initialization.

--Jonathan
 
B

Balog Pal

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.)
 
K

Keith H Duggar

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.

KHD
 
F

Francesco S. Carta

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.

Is it yet another GCC extension? In case, is it a compliant one, for
what you can tell?
 
A

Alf P. Steinbach /Usenet

* Francesco S. Carta, on 30.07.2010 18:55:
Could someone point out some reference to this requirement?

It is a requirement in C++98. There the compiler is free to go trough any dance
of temporaries created from temporaries. It is not a requirement in C++0x.


Cheers & hth.,

- Alf
 
F

Francesco S. Carta

on said:
* Francesco S. Carta, on 30.07.2010 18:55:

It is a requirement in C++98. There the compiler is free to go trough
any dance of temporaries created from temporaries. It is not a
requirement in C++0x.

If it is a requirement and not just an allowance, then MinGW 4.4.0 has a
bug, because it compiles the code below without any warning in -pedantic
mode. I don't know about -ansi mode because it seems to be broken (it
gives weird errors about wide chars).

Besides, does the following:

const T& t = *(new T);

suffer from the same issue about temporaries and copy ctor required?

//-------
#include <iostream>
#include <string>

using namespace std;

class NoCopyNoAssign {
public:
NoCopyNoAssign(string s = "[not specified]") : s(s) {}
friend ostream& operator<<(ostream& os, const NoCopyNoAssign& obj) {
os << obj.s;
return os;
}
private:
NoCopyNoAssign(const NoCopyNoAssign&);
NoCopyNoAssign& operator=(const NoCopyNoAssign&);
string s;
};

template<class T> void f(const T& passed) {
const T& local = T();
cout << "passed == " << passed << endl;
cout << "local == " << local << endl;
}

int main() {
NoCopyNoAssign ncna("initialized");
f(ncna);
int i = 42;
f(i);
}
//-------
 
A

Alf P. Steinbach /Usenet

* Francesco S. Carta, on 30.07.2010 20:01:
If it is a requirement and not just an allowance, then MinGW 4.4.0 has a
bug, because it compiles the code below without any warning in -pedantic
mode. I don't know about -ansi mode because it seems to be broken (it
gives weird errors about wide chars).

Besides, does the following:

const T& t = *(new T);

suffer from the same issue about temporaries and copy ctor required?

No, it only has the memory leak issue. :)

In this case the initializer is an lvalue of the same type, and §8.5.3/5 first
dash applies, "direct initialization".

In the rvalue case "the choice is implementation-defined" whether to bind
directly or create a temporary and copy the initializer. However, "The
constructor that would be used to make the copy shall be callable whether or not
the copy is actually done". Which is why in C++98 you can't pass a
std::auto_ptr<T>() to a std::auto_ptr<T> const& formal argument: it won't bind
directly, it requires a copy constructor, and the only one available in
std::auto_ptr is the one doesn't take const-ref and so doesn't bind rvalue.

I'm guessing that g++ implements C++0x rules here instead, with direct binding.

Btw., the wchar_t-issues: MinGW g++ does not implement full wchar_t support, in
particular, it lacks std::wostringstream & family (but has std::wstring).


Cheers & hth.,

- Alf
 
K

Kai-Uwe Bux

Francesco said:
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]
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.


Best

Kai-Uwe Bux
 
F

Francesco S. Carta

on said:
* Francesco S. Carta, on 30.07.2010 20:01:

No, it only has the memory leak issue. :)

Of course, but I would delete it afterwards ;-)
In this case the initializer is an lvalue of the same type, and §8.5.3/5
first dash applies, "direct initialization".

In the rvalue case "the choice is implementation-defined" whether to
bind directly or create a temporary and copy the initializer. However,
"The constructor that would be used to make the copy shall be callable
whether or not the copy is actually done". Which is why in C++98 you
can't pass a std::auto_ptr<T>() to a std::auto_ptr<T> const& formal
argument: it won't bind directly, it requires a copy constructor, and
the only one available in std::auto_ptr is the one doesn't take
const-ref and so doesn't bind rvalue.

I'm guessing that g++ implements C++0x rules here instead, with direct
binding.

Don't know, I didn't specify the flag for using the upcoming standard rules.
Btw., the wchar_t-issues: MinGW g++ does not implement full wchar_t
support, in particular, it lacks std::wostringstream & family (but has
std::wstring).

That explains the weird errors, thanks for the detail.
 

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

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,815
Latest member
treekmostly22

Latest Threads

Top