2

以下代码引发编译错误:

#include <stdio.h>

class Option
{
    Option() { printf("Option()\n"); };
public:
    explicit Option(const Option& other)
    {
        printf("Option(const)\n");
        *this = other;
    }

    explicit Option(Option& other)
    {
        printf("Option(non-const)\n");
        *this = other;
    }

    explicit Option(const int&)
    {
        printf("Option(value)\n");
    }
};

void foo(Option someval) {};

int main()
{
    int val = 1;
    Option x(val);
    foo(x);
}

抛出的错误是:

main.cpp:31:10: error: no matching function for call to ‘Option::Option(Option&)’
     foo(x);
          ^
main.cpp:5:5: note: candidate: ‘Option::Option()’
     Option() { printf("Option()\n"); };
     ^~~~~~
main.cpp:5:5: note:   candidate expects 0 arguments, 1 provided
main.cpp:25:6: note:   initializing argument 1 of ‘void foo(Option)’
 void foo(Option someval) 

如果我从中删除显式关键字,错误就会消失explicit Option(const Option& other)

有人可以向我解释编译错误的原因是什么吗?explicit Option(const Option& other)另外,如果和之间有区别explicit Option(Option& other)

4

1 回答 1

2

在 call中foo(x),必须创建一个新Option的,它将someVal在执行foo's body 期间变为。即x需要复制到someVal. 编译器本质上会尝试初始化Option someVal(x);(尝试 first Option(Option&), then Option(Option const&)),但它不能,因为您说过这两个构造函数都是explicit并且不应该被隐式调用。使用 C++17,您可以显式插入缺少的构造函数调用以使其工作:foo(Option(x)). 在 C++17 之前,不可能调用foo,因为编译器会不断尝试插入对构造函数的调用,Option但没有可用于插入的调用。

在标准语言中,函数调用(如foo(x)调用someVal复制初始化的参数) x。从某个类的对象或派生类的对象复制初始化该类的对象只考虑该目标类的转换构造函数。“Converting constructor”只是“constructor that is not explicit”的花哨名称。然后通过正常的重载决议选择其中最好的构造函数。由于您的构造函数都不是 not explicit因此这总是失败并且foo在 C++17 之前是不可调用的。从 C++17 开始,当参数是纯右值(如foo(Option(x)))时,调用构造函数的要求可以被回避并foo变为可调用。

对于你的问题:

explicit Option(const Option& other)另外,如果和之间有区别explicit Option(Option& other)

当然:第一个承诺它不会修改它的论点,而第二个则不会。您已经知道它们可以被定义为做不同的事情,并且重载决议会根据上下文更喜欢一个而不是另一个:

Option x(1);
Option const y(2);
Option a(x); // calls Option(Option&) if available, which may modify x; calls Option(Option const&) if not, which shouldn't modify x
Option b(y); // must call Option(Option const&) because that promises not to modify y; cannot call Option(Option&) because it may modify y
于 2020-03-27T23:32:11.500 回答