问题
class Foo
{
public:
explicit Foo() {}
explicit Foo(Foo&) {}
};
Foo d = Foo();
error: no matching function for call to 'Foo::Foo(Foo)'
I tried changing Foo(Foo&)
to Foo(Foo)
as the error suggests, which AFAIK is not a valid constructor, and sure enough I get:
error: invalid constructor; you probably meant ‘Foo (const Foo&)’
What gives? How do I resolve this? (This is on GCC by the way)
回答1:
There are two questionable things that you have in your copy constructor.
First, you've made the copy-constructor explicit (which is a questionable thing to do), so you would (in theory) need to do:
Foo d( (Foo()) );
Second, your copy constructor takes a reference and not a const
reference which means that you can't use it with a temporary Foo
.
Personally, I'd just remove explicit
from the copy-constructor and make it take a const
reference if possible.
Note that the explicit
on your default constructor has no effect.[*] explicit
only has an effect on constructors that can be called with a single parameter. It prevents them being used for implicit conversions. For constructors that take only zero or only two or more parameters, it has no effect.
[Note: there can be a difference between:
Foo d;
and
Foo d = Foo();
but in this case you have a user-declared default constructor so this doesn't apply.]
Edit:
[*] I've just double checked this and 12.3.1 [class.conv.ctor] says that you can make a default constructor explicit
. In this case the constructor will be used to perform default-initialization or value-initialization. To be honest, I don't understand the value of this as if you have a user-declared constructor then it's a non-POD type and even local objects of non-POD type are default-initialized if they don't have an initializer which this clause says can be done by an explicit
default constructor. Perhaps someone can point out a corner case where it does make a difference but for now I don't see what effect explicit
has on a default constructor.
回答2:
You don't want to mark either of those constructors as explicit - the compiler needs to use both of them, particularly the copy constructor, implicitly. What are you trying to achieve by marking them explicit?
回答3:
First, neither the default constructor nor the copy constructor should ever be explicit
. You only need to make a constructor explicit
if it takes a single argument of some other type, to prevent implicit conversion from that type. The copy constructor takes a reference to the class itself, so there is no danger of an unwanted conversion.
Second, make sure that the copy constructor takes a const
reference.
Third, Foo f;
is the right way to have a default-constructed object of class foo. Note that Foo f();
is wrong, because the compiler will interpret that as a declaration of function f()
which returns an object of class Foo
.
Fourth, if you have written your own copy constructor, then you should also write the assignment operator.
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
};
回答4:
Try without the explicit? I think that:
Foo foo = Foo()
creates an implicit copy, thus the explicit copy constructor doesn't get triggered.
Edit:
This is only half the answer. See Charles Bailey or UncleBens post for why const is necessary.
回答5:
A copy constructor shouldn't be explicit (which makes it uncallable here and in many other perfectly reasonable contexts, such as when passing or returning by value).
Next it should take the argument by const reference, since otherwise it can't bind to temporaries.
Foo f = Foo();
^^^^^
|
--- this is a temporary that cannot be passed to a function
that accepts a non-const reference
Furthermore, there is no reason to make the default constructor explicit: this keyword only makes sense for constructors (other than the copy constructor) that can be called with exactly one argument, in which case it prevents implicit conversions of other types into Foo via that constructor. For example, if a constructor taking an int were explicit, situations like these wouldn't compile:
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);
All in all:
class Foo
{
public:
Foo();
Foo(const Foo&);
//...
};
Foo x = Foo();
And furthermore, if neither of those constructors is meant to do anything, you needn't define them at all - the compiler will provide them automatically (if you define any other constructors, the default constructor will not be automatically generated, though).
回答6:
Foo d = Foo();
should be
Foo d;
The first line creates a Foo instance and then copies it to d;
回答7:
Your problem is in the instantiation. You don't need Foo d = Foo();
for a default constructor.
Keep your class the same, but try this for instantiation:
Foo d;
In fact, you don't even need Foo d = Foo(arguments);
for constructing with parameters. That should be like this:
Foo d(arguments);
回答8:
The compiler is telling you... Use this:
Foo(const Foo&) {}
回答9:
You can cure the problem in either of two ways. One (already suggested by Randolpho) is to eliminate using the copy ctor. The other is to write a proper copy ctor:
Foo (Foo const &) {}
You generally want to do both.
Edit: Looking at it, my last comment is easy to mis-construe. Quite a few classes do not need a copy ctor at all, but if you do need a copy ctor, it should normally have the form above (not explicit, and taking a const reference as the parameter).
回答10:
class Foo
{
public:
explicit Foo() {}
explicit Foo(const Foo&) {}
};
Foo d = Foo()
来源:https://stackoverflow.com/questions/2776313/foo-f-foo-no-matching-function-for-call-to-foofoofoo-huh