为什么我不能使用显式构造函数来构造 return 类型

How come I can't use explicit constructor for constructing a return type

我玩弄了显式构造函数及其行为,所以我创建了这个 class:

#include <iostream>

class X
{
public:
    explicit X(void)
    {
        std::cout << "Default constructor\n";
    }
    explicit X(X const& x)
    {
        std::cout << "Copy constructor\n";
    }
    explicit X(X&& x)
    {
        std::cout << "Move constructor\n";
    }
};

这基本上只是测试显式构造函数的存根。 然后我想尝试几种情况。所以我尝试了这个:

X foo(void)
{
    X a{};
    return a;  // ERROR: no matching constructor found!
}

int main()
{
    X w{};  // Default Constructor
    X x{w};  // Copy Constructor
    X y{std::move(x)};  // Move Constructor
    X z{foo()};
}

如您所见,我无法在 foo() 中 return a。我知道它试图用复制构造函数初始化 return 类型 Foo,但由于某种原因它不能使用它。

为什么它不能使用我提供的拷贝构造函数?我知道 explicit 规范会导致问题,因为当我将它从复制构造函数中删除时它会起作用。但是为什么?

更让我困惑的是,我可以做到以下几点:

void bar(const X& a) { /* */ }
bar(X{});

它没有抱怨。但是 bar() 不应该像 foo() 构造它的 return 类型一样构造它的参数 a 吗?

你不能,因为你说过你不希望编译器在你显式声明它时隐式使用它。

explicit X(X const& x)

但是 x 必须复制到 return 值中。只需将其更改为

X(X const& x)

一切正常。

Live on Coliru

当您 return 来自 foo:

X foo()
{
    X a{};
    return a;
}

您正在将 a 隐式复制到 foo 的 return 中。但是复制构造函数被标记为 explicit,所以这是不允许的。

我不确定是否有理由标记 copy/move 构造函数 explicit

我想你误解了explicit的意思。 explicit 构造函数将不会用于隐式类型 CONVERSIONS/CASTS。这意味着

X foo(void){
    X a{};
    return a;  // ERROR: no matching constructor found!
}

不会编译,因为您已经告诉编译器不要隐式使用复制构造函数。

我估计你要实现的是"move"而不是复制a。只要 class 中有一个(正常的)移动构造函数,a 就会被移动而不是被复制——这是默认行为。实际上,即使使用 c++99,大多数编译器也足够聪明,可以优化这个副本。