【问题标题】:C++ explicit universal reference constructor does not hide copy constructor?C++ 显式通用引用构造函数不隐藏复制构造函数?
【发布时间】:2023-03-22 18:15:01
【问题描述】:

可能我对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
}

DEMO

这是一种通用的解决方案,而不是 SFINAE 的东西,否则将适用于防止隐藏在 A 中(例如 std::enable_if_t&lt;!std::is_same&lt;std::decay_t&lt;T&gt;, A&gt;::value&gt;,参见 here)?

【问题讨论】:

  • 对于那些感兴趣的人,here 是我根据答案找到的一些解释。

标签: c++ c++11 copy-constructor universal-reference


【解决方案1】:

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

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

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

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

【讨论】:

  • 谢谢,但我没有得到答案。您能否更详细地解释一下复制A_explicit 时会发生什么?例如,您的意思是模板根本没有作为重载决议的候选提交
  • @davidhigh 实例化模板生成的函数根本没有机会被调用,因为复制初始化需要一个非显式构造函数。而对于A,它与复制构造函数同等对待,并选择最佳匹配。
【解决方案2】:

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

它确实参与了复制列表初始化 (A a = {b1};),如果被选中会导致程序格式错误。

...除非大括号内的东西是A 或从其派生的类,在这种情况下,最近的缺陷报告更改了规则,说在这种特殊情况下执行复制初始化 - 所以explicit 构造函数再次被完全忽略。

我知道,非常好教。

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

没有。因为该构造函数仍将赢得直接初始化的重载决议:

A_explicit a, b(a); // will call the constructor taking a forwarding reference

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-28
    • 1970-01-01
    • 2012-07-13
    相关资源
    最近更新 更多