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

时间:2015-05-08 07:09:53

标签: c++ c++11 copy-constructor 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
}

DEMO

这是一个通用的解决方案,而不是SFINAE的东西,否则将适用于防止隐藏A(例如std::enable_if_t<!std::is_same<std::decay_t<T>, A>::value>,见here)?

2 个答案:

答案 0 :(得分:6)

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

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

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

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

答案 1 :(得分:5)

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

它确实参与了复制列表初始化(A a = {b1};),并导致程序在选中时格式不正确。

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

非常可教,我知道。

  

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

没有。因为该构造函数仍然会为直接初始化赢得重载决策:

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