Q: why are all templated copy-constructors necessary?

C

Claudius

Hello,

in my class TopTen I need to define three constructors while only the
last one, the most general in terms of templates, should be sufficient
in my opinion:

template <typename Tnum, short Trank, bool Tcont>
TopTen<Tnum,Trank,Tcont>::TopTen( const TopTen<Tnum,Trank,Tcont> &
tten );

template <typename Tnum, short Trank, bool Tcont>
template <bool Tcont1>
TopTen<Tnum,Trank,Tcont>::TopTen( const TopTen<Tnum,Trank,Tcont1> &
tten );

template <typename Tnum, short Trank, bool Tcont>
template <typename Tnum1, bool Tcont1>
TopTen<Tnum,Trank,Tcont>::TopTen( const TopTen<Tnum1,Trank,Tcont1> &
tten );

In a testprogram all three copy-constructors are used.
When dropping the first two, however, the linker issues undefined
references.

I use g++ 3.4.4 under cygwin.

Does anyone have an idea?

Thank you very much in advance,

Claudius
 
V

Victor Bazarov

Claudius said:
Hello,

in my class TopTen I need to define three constructors while only the
last one, the most general in terms of templates, should be sufficient
in my opinion:

template <typename Tnum, short Trank, bool Tcont>
TopTen<Tnum,Trank,Tcont>::TopTen( const TopTen<Tnum,Trank,Tcont> &
tten );

As I understand it, the above is the actual copy constructor.
template <typename Tnum, short Trank, bool Tcont>
template <bool Tcont1>
TopTen<Tnum,Trank,Tcont>::TopTen( const TopTen<Tnum,Trank,Tcont1> &
tten );

This is a templated constructor (that constructs from an object of
the different type).
template <typename Tnum, short Trank, bool Tcont>
template <typename Tnum1, bool Tcont1>
TopTen<Tnum,Trank,Tcont>::TopTen( const TopTen<Tnum1,Trank,Tcont1> &
tten );

This is also a templated constructor that construct from an object of
the different type, right?
In a testprogram all three copy-constructors are used.

What does that mean? In WHAT testprogram? I don't see any testprogram.
When dropping the first two, however, the linker issues undefined
references.

I use g++ 3.4.4 under cygwin.

It usually doesn't matter in comp.lang.c++.
Does anyone have an idea?

You must be missing the fact that a templated constructor is NEVER
used in place of a copy constructor (to construct from an object of
the _same_ type).

V
 
A

Alf P. Steinbach

* Victor Bazarov:
As I understand it, the above is the actual copy constructor.

Uh... A templated constructor is never a copy constructor. As you
implicitly state below:

[snip]
You must be missing the fact that a templated constructor is NEVER
used in place of a copy constructor (to construct from an object of
the _same_ type).

This I'm not sure of. Consider copy constructor T(T&). Then when
copying from a temporary or const, I think perhaps a templated
constructor would be used instead. But this needs to be checked if ever
an issue. And the best is, as always, to avoid such corner cases... ;-)
 
C

Claudius

* Victor Bazarov:

Sorry Victor, here my testprogram I've forgotten. I use one
constructor after another and test in its implementation whether it is
invoked:
------------------------------
TopTen<int,2> A( 1, 5, 1, 5 );
A =
11, 12, 13, 14, 15,
21, 22, 23, 24, 25,
31, 32, 33, 34, 35,
41, 42, 43, 44, 45,
51, 52, 53, 54, 55;

TopTen<int,2,false> A_sliced;
A_sliced.dat_slice( A, _(2,4,2), _(2,4,2) );

cout << "--------------------" << endl;
cout << "1) TopTen( const TopTen<Tnum,Trank,Tcont> & tten ):" <<
endl;
TopTen<int,2> B( A );
cout << "B=" << B << endl;

cout << "--------------------" << endl;
cout << "2) TopTen( const TopTen<Tnum,Trank,Tcont1> & tten ):" <<
endl;
TopTen<int,2,true> C( A_sliced );
cout << "C=" << C << endl;

cout << "--------------------" << endl;
cout << "3) TopTen( const TopTen<Tnum1,Trank,Tcont1> & tten ):" <<
endl;
TopTen<float,2,true> D( A_sliced );
cout << "D=" << D << endl;
------------------------------

Thank you for your help, that was new to me!

This rises another question:

When only dropping the second Constructor, why is it missed by the
linker, why is the more general third Constructor not sufficient to
serve the second case as well?

Thank you again,
Claudius
 
V

Victor Bazarov

Alf said:
* Victor Bazarov:

Uh... A templated constructor is never a copy constructor.

Correct. But are you sure what you're looking at *is* a templated
constructor?

You're confusing a templated constructor and a constructor in a class
template. Consider

template<class T> struct A {
A() {}
A(A const& a); // non-templated copy constructor.
};

template<class S> struct B {
B() {}
template<class T> B(B<T> const& b); // templated constructor
};

// now the definitions
template<class T> A<T>::A(A<T> const&) {}
template<class S> template<class T> B<S>::B(B<T> const&) {}

int main() { A<int> ai, aii(ai); B<int> bi; B<double> bd(bi); }

Now, which one looks more like the definition you tried correcting
me about?
As you
implicitly state below:

[snip]

V
 
V

Victor Bazarov

Claudius said:
[..]
This rises another question:

When only dropping the second Constructor, why is it missed by the
linker, why is the more general third Constructor not sufficient to
serve the second case as well?

When choosing between two templates, the compiler tries to instantiate
(and use) the most specialised one. If you kept the declaration of
the "second" constructor and only removed its definition, you are in
violation of ODR. Perhaps you needed to drop the declaration as well?

In any case, since you posted only bits and pieces of your code, I am
unable to give you any specifics, and have to resort to guessing. Next
time, please, to avoid wasting your own time, post compilete code to
begin with, will you?

V
 
C

Claudius

When choosing between two templates, the compiler tries to instantiate
(and use) the most specialised one. If you kept the declaration of
the "second" constructor and only removed its definition, you are in
violation of ODR. Perhaps you needed to drop the declaration as well?

Yes, exactly! Great!
In any case, since you posted only bits and pieces of your code, I am
unable to give you any specifics, and have to resort to guessing. Next
time, please, to avoid wasting your own time, post compilete code to
begin with, will you?

Ok. Thank you again,

Claudius
 
J

James Kanze

* Victor Bazarov:
Uh... A templated constructor is never a copy constructor.

The original poster didn't give us any of the class template
definition, so it's hard to be sure, but I think that the above
is a non templated constructor of the class template.

As to why he needs to define three constructors: I rather
suspect that he declared three constructors in the class
template definition, then used each of them. And while he may
know that all three do exactly the same thing, there's no way
the compiler can know it: declare and use three functions, you
need to define three functions. It's as simple as that.

But admittedly, I'm just guessing about his class template
definition, because he forgot to post it.
As you implicitly state below:
[snip]
You must be missing the fact that a templated constructor is NEVER
used in place of a copy constructor (to construct from an object of
the _same_ type).
This I'm not sure of. Consider copy constructor T(T&). Then when
copying from a temporary or const, I think perhaps a templated
constructor would be used instead.

It will be. The presence or absence of a "copy constructor"
controls whether the compiler will generate one or not. But
there is no context where a constructor is called without full
function overload resolution occuring, even if you are copying,
and if full function overload resolution chooses an
instantiation of a template, then that's what gets called. The
only examples I can think of where this would be the case
involve const, but it can work both ways. For example, if you
provide a:
template< typename T > MyClass( T& obj ) ;
.. Since this is not a copy constructor, the compiler also
provides one, with the signature:
MyClass( MyClass const& obj ) ;
.. The template function is used for copying non-const lvalues,
and the compiler generated one for everything else.
But this needs to be checked if ever an issue.

I seem to recall a thread about it in the last year in the
moderated group.
And the best is, as always, to avoid such corner cases... ;-)

Totally agreed. But then we'd have nothing to talk about
here:).
 
A

Alex Vinokur

template<class S> struct B {
B() {}
template<class T> B(B<T> const& b); // templated constructor
// It is necessary to define templated operator= too,
// because templated _default_ operator= doesn't exist.
template said:
};

// now the definitions [snip]
template<class S> template<class T> B<S>::B(B<T> const&) {}
int main() { A<int> ai, aii(ai); B<int> bi; B<double> bd(bi); }
[snip]

Alex Vinokur
email: alex DOT vinokur AT gmail DOT com
http://mathforum.org/library/view/10978.html
http://sourceforge.net/users/alexvn
 

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,755
Messages
2,569,534
Members
45,008
Latest member
Rahul737

Latest Threads

Top