Reputation: 193
While trying to write a wrapper for shared_ptr
that would hide allocation and deallocation of memory from user while supporting inheriting classes, I have stumbled upon very weird errors suggesting that either compiler looks up wrong functions during an overload, or my knowledge regarding mixing overloads and templates is wrong. So I wrote this thing for testing:
#include <iostream>
void out(int i) {
std::cout << i << '\n';
}
template <class T>
struct Inst {
template <class TT>
Inst(const TT &) {out(1);}
Inst(const Inst &) {out(2);}
template <class TT>
Inst(TT &&) {out(3);}
Inst(Inst &&) {out(4);}
Inst() {out(-1);}
~Inst() {out(1000);}
};
class K {};
class KK : K {};
int main() {
out(3000);
K k; KK kk; Inst<K> i;
Inst<K> I1{k};
Inst<K> I2{kk};
Inst<K> I3{i};
Inst<K> I4{K()};
Inst<K> I5{KK()};
Inst<K> I6{Inst<K>()};
out(2000);
}
What I would reasonably expect would be I1
and I2
writing 1
, I3
writing 2
, I4
and I5
writing 3
and I6
writing 4
, and at least two other objects writing -1
at various points. When compiled with gcc 4.8.2 using -std=c++11
, however, my machine skipped one of objects, and wrote 3
for every other non-automatic constructor called. What am I doing wrong?
Upvotes: 3
Views: 92
Reputation: 52365
The TT&&
in Inst(TT &&) {out(3);}
is somewhat special. So, special that there is even a special "term" coined for them called universal reference
.
In short TT&&
is not what you think it is. There are two things that come into play here: Reference Collapsing and Template Deduction
Since TT
is a template parameter and you stuck &&
in front of it, this is what T&&
becomes in your example:
Inst<K> I1{k}; ---> Inst(K&)
Inst<K> I2{kk}; ---> Inst(KK&)
Inst<K> I3{i}; ---> Inst(Inst<K>&)
Inst<K> I4{K()}; ---> Inst(K&&)
Inst<K> I5{KK()} ---> Inst(KK&&)
What happens is TT&&
becomes an exact match and is the selected constructor for all the calls you make, which is why you see 3
for each one (except for i
and I6
).
For further reading, please see:
Universal References and the Copy Constructor.
Upvotes: 6