C++模板专业化:意外函数重载查找结果

sta*_*321 3 c++ templates specialization template-specialization

虽然尝试编写一个包装器shared_ptr会在支持继承类的同时隐藏用户的内存分配和释放,但我偶然发现了一些非常奇怪的错误,这些错误表明编译器在重载期间查找错误的函数,或者我对混合重载和模板的了解是错误.所以我写了这个东西用于测试:

#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);
}
Run Code Online (Sandbox Code Playgroud)

我会合理地期望会I1I2写作1,I3写作2,I4以及I5写作3I6写作4,以及其他至少两个对象写-1在不同的点.-std=c++11然而,当使用gcc 4.8.2编译时,我的机器跳过了一个对象,并3为所有其他非自动构造函数编写了.我究竟做错了什么?

Jes*_*ood 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&&)
Run Code Online (Sandbox Code Playgroud)

发生的事情TT&&变成了一个完全匹配,并且是你所做的所有调用的选定构造函数,这就是为什么你看到3每个调用(除了iI6).

如需进一步阅读,请参阅:

通用引用和复制构造函数.

使用前进的优点.