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

时间:2014-01-27 21:03:22

标签: c++ templates template-specialization 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);
}

我理所期望的是I1I2撰写1I3撰写2I4和{{1}写I53I6,至少另外两个对象在不同点写4。然而,当使用-1使用gcc 4.8.2编译时,我的机器跳过了一个对象,并为每个其他非自动构造函数写了-std=c++11。我做错了什么?

1 个答案:

答案 0 :(得分: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和{{1}})。

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

Universal References and the Copy Constructor

Advantages of using forward