Pergunta

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?

Foi útil?

Solução

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top