C++显式通用引用构造函数不隐藏拷贝构造函数?
C++ explicit universal reference constructor does not hide copy constructor?
可能是我对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
}
这是一个通用的解决方案,而不是 SFINAE 的东西,否则人们会应用它来防止隐藏在 A
中(例如通过 std::enable_if_t<!std::is_same<std::decay_t<T>, A>::value>
,请参见 here)?
在 A
中,复制构造函数 未隐藏。 编译器一如既往地隐式声明它。它只是 失去重载决议 因为它的参数类型 (const A&
) 与构造函数模板特化的参数 (A&
) 相比有额外的 cv 限定。如果你愿意
auto b = static_cast<const A&>(a);
您会看到将调用复制构造函数。
在 A_explicit
中,模板根本没有作为重载决议的候选者提交,因为它被声明为 explicit
。隐式声明的复制构造函数仍然存在,就像在A
中一样,所以它被调用。
标记为 explicit
的构造函数在复制初始化期间不参与重载决策(A a = b;
,等等)。
它确实参与了复制列表初始化(A a = {b1};
),如果选择它会导致程序格式错误。
...除非大括号内的东西是 A
或从中派生的 class,在这种情况下,最近的缺陷报告更改了规则,说在这种特殊情况下复制- 改为执行初始化 - 因此 explicit
构造函数再次被完全忽略。
非常好教,我知道。
Is that a general solution instead of the SFINAE stuff one would apply
otherwise to prevent the hiding in A?
没有。因为该构造函数仍将赢得直接初始化的重载决议:
A_explicit a, b(a); // will call the constructor taking a forwarding 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
}
这是一个通用的解决方案,而不是 SFINAE 的东西,否则人们会应用它来防止隐藏在 A
中(例如通过 std::enable_if_t<!std::is_same<std::decay_t<T>, A>::value>
,请参见 here)?
在 A
中,复制构造函数 未隐藏。 编译器一如既往地隐式声明它。它只是 失去重载决议 因为它的参数类型 (const A&
) 与构造函数模板特化的参数 (A&
) 相比有额外的 cv 限定。如果你愿意
auto b = static_cast<const A&>(a);
您会看到将调用复制构造函数。
在 A_explicit
中,模板根本没有作为重载决议的候选者提交,因为它被声明为 explicit
。隐式声明的复制构造函数仍然存在,就像在A
中一样,所以它被调用。
标记为 explicit
的构造函数在复制初始化期间不参与重载决策(A a = b;
,等等)。
它确实参与了复制列表初始化(A a = {b1};
),如果选择它会导致程序格式错误。
...除非大括号内的东西是 A
或从中派生的 class,在这种情况下,最近的缺陷报告更改了规则,说在这种特殊情况下复制- 改为执行初始化 - 因此 explicit
构造函数再次被完全忽略。
非常好教,我知道。
Is that a general solution instead of the SFINAE stuff one would apply otherwise to prevent the hiding in A?
没有。因为该构造函数仍将赢得直接初始化的重载决议:
A_explicit a, b(a); // will call the constructor taking a forwarding reference