2014-01-27 2 views
3

При попытке написать обертку для shared_ptr, которая скроет выделение и освобождение памяти от пользователя при поддержке наследующих классов, я наткнулся на очень странные ошибки, предлагая, чтобы либо компилятор искал неправильные функции во время перегрузки, или мои знания относительно смешивания перегрузок и шаблонов неверны. Так что я написал эту вещь для тестирования:Специализация по шаблону C++: неожиданный результат поиска перегрузки функции

#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); 
} 

Что бы разумно ожидать, будет I1 и I2 писать 1, I3 писать 2, I4 и I5 писать 3 и I6 писать 4, и по крайней мере два других объекта написания -1 в разных точках. Однако, когда скомпилировано gcc 4.8.2 с использованием -std=c++11, моя машина пропустила один из объектов и написала 3 для каждого вызываемого неавтоматического конструктора. Что я делаю не так?

+0

Я думаю, что вы столкнулись с некоторой путаницей о '&&' и "универсальных ссылках". См.: Http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers – Chad

+1

Вы можете найти [это проще для чтения] (http://ideone.com/11NW07). – WhozCraig

ответ

6

TT&& в Inst(TT &&) {out(3);} - несколько особый. Итак, особенное, что для них есть даже специальный термин, называемый universal reference.

Короткий TT&&не что вы думаете. Есть две вещи, которые приходят в игру здесь: Ссылка Свертывание и Шаблон Вычет

Поскольку TT является параметром шаблона, и вы застряли && перед ним, это то, что T&& становится в вашем примере:

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

Что происходит TT&& становится точным соответствием и выбранный конструктор для всех вызовов, которые вы делаете, поэтому вы видите 3 для каждого из них (за исключением i и I6).

Для дальнейшего чтения, см:

Universal References and the Copy Constructor.

Advantages of using forward.

+1

Ну, это именно так. Святая моля, это удивительный кусок синтаксиса. Наверное, я просто не могу заставить это делать то, что я думал, что это будет вообще? Во всяком случае, спасибо, что указал на этот термин. – stan423321