代码
#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&”,而p()不是const。其次,用“a”(const berlp&)初始化“mem”(berlp&)不起作用。似乎“derp(const T&a)”中的“const”什么也没做。最后,为什么它甚至使用第一个构造函数而不使用模板化的构造函数,而后者似乎可以在不破坏const的情况下完成所有这些工作?derp<const berlp &> h(one);
:当另一个似乎正是我们所追求的时,为什么此调用使用模板化构造函数?这并不是一个太可怕的问题,因为它似乎并没有破坏任何东西,但是它的确可以让您修改构造函数中传递的berlp,而其他构造函数(不应)应该不这样做。所以,我要么很困惑,要么出事了!请帮忙!
最佳答案
这里确实有多个问题:
derp<berlp&>(one)
使用第一个构造函数?构造函数的声明是
derp(T const&)
,它变成derp(berlp& const&)
并折叠成derp(berlp&)
,因为没有诸如const
引用或引用引用之类的东西。在8.3.2 [dcl.ref]第6段中指出:显然,将
berlp&
传递给采用berlp&
的构造函数是完全匹配的,并且模板构造函数无法做得更好。因此,选择了非模板构造函数。 derp<berlp&>(one)
调用berlp
起作用?这里没有真正的惊喜:
mem
的类型为berlp&
,并使用berlp&
进行了初始化,因此所有非const
成员均按预期工作。 derp<berlp const&>
并传递berlp&
时,模板构造函数是一个完美的选择,显然是选择了。刚刚使用berlp const&
初始化berlp&
类型的成员变量,该隐式转换为berlp const&
。也不奇怪。 我认为您对参考折叠规则有些困惑。将
const
放在错误的位置也无济于事:将const
放到正确的位置实际上应该可以清楚地消除大部分混乱,这是my preference的一部分,可以将ojit_code放到正确的位置。