class Foo
{
public:
explicit Foo() {}
explicit Foo(Foo&) {}
};
Foo d = Foo();
错误:没有匹配函数来调用'Foo :: Foo(Foo)'
我尝试将Foo(Foo&)
更改为Foo(Foo)
,因为错误显示,AFAIK不是有效的构造函数,而且我确实得到了:
错误:构造函数无效;你可能意味着'Foo(const Foo&)'
是什么给出的?我该如何解决这个问题? (顺便说一下,这是在GCC上)
答案 0 :(得分:12)
您的复制构造函数中有两个可疑的东西。
首先,你已经复制构造函数是显式的(这是一个值得怀疑的事情),所以你(理论上)需要这样做:
Foo d( (Foo()) );
其次,您的复制构造函数采用引用而不是const
引用,这意味着您不能将其与临时Foo
一起使用。
就个人而言,我只是从复制构造函数中移除explicit
,并尽可能使用const
引用。
请注意,默认构造函数上的explicit
无效。[*] explicit
仅对可以使用单个参数调用的构造函数产生影响。它可以防止它们用于隐式转换。对于仅采用零或仅采用两个或更多参数的构造函数,它不起作用。
[注意:可能存在以下差异:
Foo d;
和
Foo d = Foo();
但在这种情况下,您有一个用户声明的默认构造函数,因此不适用。]
修改强>
[*]我只是仔细检查过这个,12.3.1 [class.conv.ctor]说你可以创建一个默认的构造函数explicit
。在这种情况下,构造函数将用于执行 default-initialization 或 value-initialization 。老实说,我不理解这个的价值,好像你有一个用户声明的构造函数然后它是一个非POD类型,如果他们没有初始化程序,甚至非POD类型的本地对象是默认初始化的该子句所说的可以由explicit
默认构造函数完成。也许有人可以指出它确实有所作为的一个极端情况但是现在我没有看到explicit
对默认构造函数有什么影响。
答案 1 :(得分:5)
您不希望将这些构造函数中的任何一个标记为显式 - 编译器需要隐式使用它们,尤其是复制构造函数。你想通过明确标记来实现什么目标?
答案 2 :(得分:4)
首先,默认构造函数和复制构造函数都不应该是explicit
。如果构造函数采用其他类型的单个参数,则只需要构造一个构造函数explicit
,以防止从该类型进行隐式转换。复制构造函数接受类本身的引用,因此不存在不希望的转换的危险。
其次,确保复制构造函数采用const
引用。
第三,Foo f;
是拥有类foo的默认构造对象的正确方法。请注意Foo f();
是错误的,因为编译器会将其解释为函数f()
的声明,它返回类Foo
的对象。
第四,如果你已经编写了自己的复制构造函数,那么你也应该编写赋值运算符。
class Foo
{
Foo() {} // no need to make explicit. Nothing to convert from.
Foo(const &Foo f) {} // again, nothing wrong with conversion from Foo to Foo
explicit Foo(int a) {} // need explicit to prevent accidental passing of an int
// to a function that takes Foo as an argument
};
答案 3 :(得分:3)
没有明确的尝试?我认为:
Foo foo = Foo()
创建一个隐式副本,因此不会触发显式复制构造函数。
编辑:
这只是答案的一半。请参阅Charles Bailey或UncleBens的帖子,了解为什么const是必要的。
答案 4 :(得分:3)
复制构造函数不应该是显式(这使得它在这里以及许多其他完全合理的上下文中都是不可调用的,例如传递或按值返回时)。
接下来它应该通过 const 引用来获取参数,否则它无法绑定到临时值。
Foo f = Foo();
^^^^^
|
--- this is a temporary that cannot be passed to a function
that accepts a non-const reference
此外,没有理由使默认构造函数显式:此关键字仅对可以使用一个参数调用的构造函数(复制构造函数除外)有意义,在这种情况下它通过该构造函数防止其他类型隐式转换为Foo。例如,如果采用 int 的构造函数显式,则这些情况将无法编译:
Foo f;
f = 1; //assuming no operator= overload for (types convertible from) int
//this implicitly performs f = Foo(1);
Foo g = 10;
void x(Foo);
x(20);
总而言之:
class Foo
{
public:
Foo();
Foo(const Foo&);
//...
};
Foo x = Foo();
此外,如果这些构造函数都不打算做任何事情,你根本不需要定义它们 - 编译器会自动提供它们(如果你定义任何其他构造函数,默认构造函数将不会自动生成,不过)。
答案 5 :(得分:2)
你的问题在于实例化。对于默认构造函数,您不需要Foo d = Foo();
。
让你的课程保持不变,但试试这个实例化:
Foo d;
实际上,您甚至不需要Foo d = Foo(arguments);
来构造参数。那应该是这样的:
Foo d(arguments);
答案 6 :(得分:2)
Foo d = Foo();
应该是
Foo d;
第一行创建一个Foo实例,然后将其复制到d;
答案 7 :(得分:1)
编译器告诉你......使用:
Foo(const Foo&) {}
答案 8 :(得分:0)
您可以通过两种方式解决问题。一个(已经由Randolpho建议)是消除使用复制ctor。另一种是写一个正确的副本ctor:
Foo (Foo const &) {}
您通常希望同时执行这两项操作。
编辑:看一下,我的上一条评论很容易被误解。很多类不根本不需要复制ctor,但是如果你需要复制ctor,它通常应该有上面的表格(不明确,并采取const参考作为参数)。
答案 9 :(得分:-1)
class Foo
{
public:
explicit Foo() {}
explicit Foo(const Foo&) {}
};
Foo d = Foo()