C++ template specialization: unexpected function overload lookup result

c++, specialization, template-specialization, templates

Solution

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.

Advantages of using forward.

Problem

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?

Original source

Related problems