以下代码会引发编译错误:
#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关键字,错误就会消失
谁能给我解释一下编译错误的原因是什么?
另外,显式选项(const Option& other)
和显式选项(Option& other)
之间是否有区别?
最佳答案
通话中foo(x)
,一个新的Option
必须创建,它将成为 someVal
foo
执行期间的 body 。即x
需要复制到 someVal
。编译器本质上尝试初始化 Option someVal(x);
(首先尝试 Option(Option&)
,然后 Option(Option const&)
),但它不能,因为你说这两个构造函数都是 explicit
并且不应该被隐式调用。使用 C++17,您可以显式插入缺少的构造函数调用以使其正常工作:foo(Option(x))
。在C++17之前,不可能调用foo
,因为编译器将继续尝试将对构造函数的调用插入 Option
但没有一个可用于插入。
在标准语言中,函数调用如 foo(x)
调用参数 someVal
从x
复制初始化 。从某个类或派生类的对象复制初始化该类的对象时,仅考虑该目标类的转换构造函数。 “转换构造函数”只是“不是 explicit
的构造函数”的一个奇特名称。然后通过正常的重载决策选择其中最好的构造函数。因为您的构造函数没有不是 explicit
,这总是失败并且 foo
在 C++17 之前是不可调用的。从 C++17 开始,当参数是纯右值(如 foo(Option(x))
)时,可以回避调用构造函数的要求,并且 foo
变得可调用。
对于你的附带问题:
Also, if there a difference between
explicit Option(const Option& other)
andexplicit Option(Option& other)
?
当然:第一个 promise 不会修改其参数,而第二个则不会。您已经知道它们可以被定义为执行不同的操作,并且重载解析将根据上下文优先选择其中之一:
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
关于C++:使用显式关键字的编译错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60895192/