C ++模板Rvalue Ctor与Const参考Ctor

时间:2013-10-01 04:13:44

标签: c++ templates c++11 constructor

代码

#include <iostream>

using namespace std;

#define PF         cout << __PRETTY_FUNCTION__ << endl;

class berlp {
public:
    berlp() { }
    void p() { }
};

template <typename T>
class derp {
public:
    derp() = default;

    derp(const T & a) : mem(a) {
        a.p();
        mem.p();

        PF
    }

    template <typename U>
    derp(U && a) : mem(std::forward<U>(a)) {
        PF
    }

    T       mem;
};

int main(int argc, const char * argv[])
{
    berlp                   one;
    derp<berlp &>           f(one);     // problems with this list below
    derp<const berlp &>     h(one);     // problem with this follows

    return 0;
}

使用XCode和CLang输出 这一切都编译得很好,这是输出......

derp<berlp &>::derp(const T &) [T = berlp &]
derp<const berlp &>::derp(U &&) [T = const berlp &, U = berlp &]

问题

derp<berlp &> f(one);:derp构造函数中的a.p()应该失败,因为“a”是“const berlp&amp;”参考折叠后,p()不是常量。其次,用“a”(const berlp&amp;)初始化“mem”(berlp&amp;)不应该起作用。似乎“derp(const T&amp; a)”中的“const”只是没有做任何事情。最后,为什么它甚至使用第一个构造函数而不是模板化的构造函数,似乎它会在不破坏const的情况下完成所有这些?

derp<const berlp &> h(one);:为什么这个调用使用模板化的构造函数,而另一个似乎正是我们追求的?这不是一个太糟糕的问题,因为它似乎没有破坏任何东西,但它确实允许你修改构造函数中传递的berlp,而另一个构造函数(据说)不应该。

所以,我要么非常困惑,要么出现了什么!请帮忙!

1 个答案:

答案 0 :(得分:1)

这里确实存在多个问题:

  1. 为什么derp<berlp&>(one)使用第一个构造函数?

    构造函数的声明为derp(T const&),变为derp(berlp& const&)并折叠为derp(berlp&),因为没有const引用或引用引用。这在8.3.2 [dcl.ref]第6段中说明:

      

    如果typedef(7.1.3),类型模板参数(14.3.1)或decltype-specifier(7.1.6.2)表示类型TR是对类型T的引用,则尝试创建类型“对cv TR的左值引用”创建类型“对T的左值引用”,而尝试创建类型“对cv TR的右值引用”则创建类型TR。

    显然,将berlp&传递给采用berlp&的构造函数是完全匹配的,模板构造函数不能做得更好。因此,选择了非模板构造函数。

  2. 为什么用derp<berlp&>(one)调用berlp

    这里没有真正的惊喜:mem的类型为berlp&,并使用berlp&进行初始化,因此非const成员的工作正常。

  3. 使用derp<berlp const&>并传递berlp&时,模板构造函数是完美的匹配,显然是选择的。 berlp const&类型的成员变量刚刚用berlp&初始化,隐式转换为berlp const&。这里也不足为奇。

  4. 我认为你对参考折叠规则感到有些困惑。将const置于错误的位置也无济于事:将其置于右侧实际上应该清楚地显示大部分混淆,并且my preference的一部分将const置于右侧