There is a Koords class and a copy constructor for it:

 Koords(); Koords(Koords &, unsigned = 0, unsigned = 0); 

Moreover, if I declare it as explicit , then Koords return to function in the function, such as:

 Koords fun() { return Koords{}; } 

the compiler writes that there is no suitable constructor .. But which one? The copy constructor is there and it has Koords & in the first argument, so there seems to be no conversions. But the compiler tells me the opposite ...

  • one
    How about a minimal reproducible example ? - αλεχολυτ
  • one
    If this is going to vc ++, then this is a compiler bug. - VTT
  • @alexolut see above. Or is a minimal example not enough for you? Or do you have any problems to reproduce it? - Andrej Levkovitch
  • one
    Yeah, the problem. In fun , you use the default constructor, but its presence is not specified in the code. Those. The example is not complete. An ideal example when the code can be just ctrl + c, ctrl + v and look at the result. Without thinking anything out and pasting pieces from different parts. - αλεχολυτ
  • Yes, here is the usual Koords() - everything. - Andrej Levkovitch

2 answers 2

  • Obviously you have fields in the class and no default invariant is set. Because you have an error: there is no corresponding function to call in Koords :: Koords(){}
  • Your copy constructor does not perceive the compiler as a copy constructor, in order to avoid modifying the copied object (there is no const specifier). The compiler may simply consider this as an undefined constructor and report that it is an incorrect initialization from the rvalue типа 'Koords' .

    This is the second mistake.

I will write as it should:

 class Koords{ public: Koords() {} Koords(const Koords &, unsigned = 0, unsigned = 0); }; 

Now you can safely return the object with the initializer by default. explicit для коструктора коопирования? .. When you write a copy constructor, you already explicitly copy .. (Although this does not apply to the answer to the question)

 Koords fun() { return Koords{}; } 

If you do not write a constructor, then the compiler does not know how to initialize your object. We'll have to return just an uninitialized object, replacing curly brackets with round brackets. I hope you understand, although I will never say that I can explain well

  • "you have an error: there is no corresponding function to call in Koords :: Koords () {}" - no need to invent it, if this constructor were not available, the code would not work before adding explicit. The copy constructor is not called here at all. In addition, the OP did not give an example demonstrating the stated problem, so there is another question whether it really was and what it was. - VTT
  • @VTT, where does such confidence come from that I am inventing, not you. I do not agree with you, even if you consider yourself to be the greatest expert - AR Hovsepyan
  • How is const related to endless copying? - Croessmah
  • @Croessmah, yes, I didn’t write a bit (carelessness error), but once the copied object is not constant, you can write something like this in the CC body and not only that. But thank you for warning. I'll fix it now - AR Hovsepyan
  • The copy constructor is not required to accept a reference to a constant. The first parameter can be just a link, and the rest are set by default. - Croessmah

In your case of a suitable copy constructor, this is not your reason, because the first parameter of your copy constructor is declared as a non-constant lvalue reference. This link cannot be linked to the temporary Koords{} object Koords{} . Therefore, up to C ++ 17 (see below), this cannot work in principle, and explicit nothing to do with it.


As for explicit on the copy constructor ... The copy constructor by definition has always been a special case of the conversion constructor. Declaring a copy constructor as an explicit produces the same effect on it as on any other single-argument constructor. Such an explicit constructor will be used only in contexts corresponding to direct initialization (direct-initialization), and will not be used in contexts corresponding to copy initialization (copy-initialization)

 struct S { S() {} explicit S(const S&) {} }; int main() { S s; S a(s); // OK S b = s; // Ошибка } 

Returning a value from a function through return is done according to the rules of copy initialization . Therefore, the explicit copy constructor cannot be used there.

 S foo() { S s; return s; // Ошибка } 

Note that in C ++ 14 such options are erroneous for the same reason.

 return S(s); return S(); return S{}; 

but starting with C ++ 17, these options are already correct because of guaranteed copy elision.

Interestingly, even in C ++ 14 the correct one is

 S foo() { return {}; } 

But I do not remember offhand what “corner” of the standard makes it possible.

  • Does copy-elision cancel semantic rules? - Croessmah
  • @Croessmah: Guaranteed copy-elision in C ++ 17 cancels. That is, in contexts with guaranteed copy-elision, there is no longer a requirement for an accessible copy constructor. - AnT
  • Thank you for the clarification. - Croessmah
  • From such answers, of course, more benefits ... - AR Hovsepyan