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

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)

DEMO

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

Bri*_*ian 6

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

auto b = static_cast<const A&>(a);
Run Code Online (Sandbox Code Playgroud)

你会看到将调用复制构造函数.

A_explicit,模板不会作为重载决策的候选者提交,因为它已被声明explicit.隐式声明的复制构造函数仍然存在,就像它在里面一样A,所以它被调用.


T.C*_*.C. 5

标记为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)