views:

440

answers:

10
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)

+2  A: 

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);
Randolpho
`Foo d = Foo()` was just a simplification to generate the error. I could have had `Foo d;` and `Foo k = d;` somewhere else
Kyle
@Kyle: From the many comments you've now left, I can see you were deliberately trying to invoke the copy constructor. I wish you had said so explicitly in your question. I can't find anywhere in your question that you imply that you even know what a copy constructor *is* ; you just posted code and said "why is it brokens?" I made the assumption (yeah, yeah) that you were simply doing it wrong. `Foo d = Foo();` certainly invokes the copy constructor on that fleeting `Foo` instance, but it's something you shouldn't ever actually *do*.
Randolpho
As implied in its title, my question is regarding the bizarre error message, which does not seem to be an obvious result from the given code. I have yet to master the skill of cornering a question so precisely that nobody can possibly answer the wrong question. Please edit your answer so SO will allow me to upvote you.
Kyle
@Kyle: Heh... C++ compiler errors tend toward the bizarre in general. Regarding your question, I'd say stating your intent explicitly is a Good Thing (tm). In this case... let's say your intent was to invoke the copy constructor, but the compiler said you didn't have one, when you clearly did, so WTF? Regarding the assumption I made, don't blame yourself, blame me. The problem is that so many people post garbage questions that we tend to have to try to find the "real question". I should have been more diligent.
Randolpho
+2  A: 
Foo d = Foo();

should be

Foo d;

The first line creates a Foo instance and then copies it to d;

Tom
Correct, but not an answer to the question -- `Foo d = Foo()` was just a simplification to generate the error. I could have had `Foo d;` and `Foo k = d;` somewhere else.
Kyle
+10  A: 

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.

Charles Bailey
Why the extra set of parentheses?
clahey
@clahey: To get around the most vexing parse.
James McNellis
Now that James has given the correct answer I can just say: because I'm a closet lisp fan.
Charles Bailey
I will do the same thing I do for all questions I don't know the answer to: upvote the one that looks the *"most right."* Congratulations Charlie.
BlueRaja - Danny Pflughoeft
Next question. The difference between Foo d; and Foo d = Foo(); is that in one case you call the default constructor, while in the other you create a temporary, call the default constructor, and then call the copy constructor. Assuming the two constructors have the right semantics, how is the second case ever useful?
clahey
@clahey: If you have a class type with no user-declared constructor or a POD type, then `Foo d;` leaves `d` uninitialized and `Foo d = Foo();` value initializes `d`. As for calling the copy constructor, the compiler is allowed to elide the call to the copy constructor (i.e., not actually call it) as long as the copy constructor is callable. Basically this allows the object to be constructed in-place rather than constructing the temporary then copying it.
James McNellis
@clahey: Within a template and the template Parameter `Foo`, the construct `Foo d = Foo()` is useful, because if `Foo` is a primitive type, then `d` leaves uninitialized if `Foo d` was used. Related: http://stackoverflow.com/questions/2143022/how-to-correctly-initialize-variable-of-template-type
Christian Ammer
I *want* to accept this question but I can't yet. I have a problem with this statement: "Note that the explicit on your default constructor has no effect." On visual studio, `explicit Foo() {}` results in "error C2520: 'Foo::Foo' : no non-explicit constructor available for implicit conversion" whereas just `Foo() {}` results in "error C2558: class 'Foo' : no copy constructor available or copy constructor is declared 'explicit'", therefore the explicit on the default constructor has an effect. I don't understand WHY though.
Kyle
@Kyle: I've updated my answer. The standard allows you to make a default constructor explicit, but you should still be able to _value-intitialize_ with it in `Foo d = Foo();` so I can only assume that it's a Visual Studio "bug", albeit a pretty obscure one.
Charles Bailey
+3  A: 

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.

clahey
This is the correct answer. Furthermore, there's no reason to make the copy constructor explicit to begin with. Explicit constructors are meant to keep you from accidentally, implicitly converting types.
Noah Roberts
This is half the answer.
clahey
+1  A: 

The compiler is telling you... Use this:

Foo(const Foo&) {}
KZ
Countered down-vote. It is quite literally telling what the signature should look like. (Not what it should do - nothing - though.)
UncleBens
+5  A: 

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?

anon
To answer your question: I want to eliminate any suprises caused by a conversion I didn't want to happen (... by having the compiler raise an error).
Kyle
@Kyle But you do want the the compiler to be able to make copies - that's not a conversion. And neither is default construction.
anon
Right, but I want it to bomb if I ever try to do `Foo f = Bar()` where `Bar` happily allows itself to be converted to a Foo by providing an `operator Foo()` (I think I have that thought process right..)
Kyle
@Kyle I think not. The copy constructor does not perform conversions - if you want to prevent that code, you need to prevent Bar being convertible to Foo, not ban copying of Foo. There is also the issue of _why_ you want to prevent conversions in the first place - they are generally a good things, and give C++ a lot of its power and usability.
anon
A: 

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).

Jerry Coffin
Dennis Zickefoose
@Dennis:If you like it, that's fine -- but a copy constructor that opens the door to modifying the object being copied isn't what I'd call "proper".
Jerry Coffin
A: 
class Foo
{
public:
    explicit Foo() {}
    explicit Foo(const Foo&) {}
};

Foo d = Foo()
Betamoo
why negative 1 ?
Betamoo
it wasn't me, but I can tell you that still doesn't compile.
Kyle
+3  A: 

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).

UncleBens
This is the best answer so far, but I would add more text about what the correct thing to do is.
clahey
You can call an explicit copy constructor using direct initialization (e.g., `Foo f; Foo g(f);`).
James McNellis
@James: Thanks, added a clarification.
UncleBens
Nathan Ernst
+3  A: 
Dima