C++ 显式通用引用构造函数不隐藏复制构造函数?

问题描述 投票:0回答:2

可能我对

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>
,请参阅这里)?

c++ c++11 copy-constructor universal-reference
2个回答
6
投票

A
中,复制构造函数未隐藏。编译器像往常一样隐式声明它。它只是失去了重载解析,因为与构造函数模板特化的参数(
const A&
)相比,它的参数类型(
A&
)具有额外的cv限定。如果你愿意的话

auto b = static_cast<const A&>(a);

您会看到复制构造函数将被调用。

A_explicit
中,模板根本不会作为候选者提交到重载解析,因为它被声明为
explicit
。隐式声明的复制构造函数仍然存在,就像在
A
中一样,因此它被调用。


5
投票

标记为

explicit
的构造函数在复制初始化期间不参与重载解析(
A a = b;
等)。

它确实参与复制列表初始化(

A a = {b1};
),并且如果选择它会导致程序格式错误。

...除非大括号内的内容是

A
或从中派生的类,在这种情况下,最近的缺陷报告更改了规则,表示在这种特殊情况下会执行复制初始化 - 所以
explicit 
构造函数再次被完全忽略(demo)。

非常有教养,我知道。

这是一种通用解决方案,而不是 SFINAE 的解决方案吗? 否则是为了防止隐藏在A中?

不。因为该构造函数仍然会赢得直接初始化的重载解析:

A_explicit a, b(a); // will call the constructor taking a forwarding reference
© www.soinside.com 2019 - 2024. All rights reserved.