dav*_*igh 2 c++ copy-constructor c++11 universal-reference
可能我的理解explicit是不够的,但我想知道为什么在下面的代码中,当我将后者声明为后,复制构造函数不会被异步引用构造函数隐藏explicit.
struct A
{
A() = default;
template<typename T>
A(T&& t) { std::cout<<"hides copy constructor"<<std::endl; }
};
struct A_explicit
{
A_explicit() = default;
template<typename T>
explicit A_explicit(T&& t) { std::cout<<"does not hide copy constructor?"<<std::endl; }
};
int main()
{
A a;
auto b = a; (void) b; //prints "hides copy constructor"
A_explicit a_exp;
auto b_exp = a_exp; (void) b_exp; //prints nothing
}
Run Code Online (Sandbox Code Playgroud)
这是一个通用的解决方案,而不是SFINAE的东西,否则将适用于防止隐藏A(例如std::enable_if_t<!std::is_same<std::decay_t<T>, A>::value>,看到这里)?
在A,不隐藏复制构造函数.编译器会像往常一样隐式声明它.它只是失去了重载决策,因为它的参数type(const A&)与构造函数template(A&)的特化参数相比具有额外的cv限定.如果你愿意的话
auto b = static_cast<const A&>(a);
Run Code Online (Sandbox Code Playgroud)
你会看到将调用复制构造函数.
在A_explicit,模板不会作为重载决策的候选者提交,因为它已被声明explicit.隐式声明的复制构造函数仍然存在,就像它在里面一样A,所以它被调用.
标记为explicit在复制初始化期间不参与重载解析的构造函数(A a = b;以及其他内容).
它确实参与了copy-list-initialization(A a = {b1};),如果选中,会导致程序格式错误.
...除非大括号内的东西是一个A或从中派生的类,在这种情况下,最近的缺陷报告改变了规则,说在这种特殊情况下执行复制初始化 - 所以explicit构造函数再次被忽略完全.
我知道,非常可教.
这是一个通用的解决方案而不是SFINAE的东西,否则将适用于防止隐藏在A?
不会.因为该构造函数仍然会为直接初始化赢得重载决策:
A_explicit a, b(a); // will call the constructor taking a forwarding reference
Run Code Online (Sandbox Code Playgroud)