How it comes that operation like foo = int can be done by both foo(int) (conversion constructor) and foo::operator=(int) (overloaded assignment operator)? When one be called instead of other (maybe one is rudimentary)?
#include <iostream>
class foo
{
public:
foo(){}
foo(int r_value)
{
std::cout << "\nfoo::foo(int)\n";
}
void operator=(int r_value)
{
std::cout << "\nfoo::operator=(int)\n";
}
};
int main()
{
foo f;
f = 57;
return 0;
}
Code above makes operator=(int) to run when both exist and foo(int) if operator=(int) is commented (or opposite).
This is basic overload resolution. Both overloads are viable:
Binding 57 to foo::operator=(int) (exact match)
Implicitly converting 57 to foo via the converting constructor, and binding the temporary foo object to the implicitly defined foo::operator=(foo const &).
Since the latter requires more conversions than the former, it is a less-good match, and the former overload is chosen.
You can still achieve the second call by making it explicit:
f = foo(57); // binds perfectly to foo::operator=(foo const &)
The full set of rules for overload resolution are rather long and involved, but in individual cases like this the answer is straight-forward. See 13.3 ([over.match]) for the full, gory details, though.
There is a difference:
foo a = 10;
Calls foo::foo(int)
foo a;
a = 10;
Calls foo::operator=(int) in a
Both of the implementations are different. The first is a Constructor and the second is an assignment. The Use cases varies, and each of them would be called accordingly based on the use case.
Use Case
The Constructor is called foo::foo(int)
foo f = 57;
The Assignment is called foo::operator=(int)
foo f;
f = 57;
Note
Using assignment in the above use case and in your example has more overhead, as it called the default constructor along with the assignment.
For this statement
f = 57;
the compiler at first considers all functions operator =. There are two such functions: the explicitly defined by you and the copy assignment operator implicitly defined by the compiler. The first one is the best suitable function. So it is called.
If you will comment this assignment operator then the compiler has only one function operator =. It is the implicitly defined copy assignment operator. But it can not be applied directly. So the compiler seeks a way to convert supplied argument to type foo. And it can do this by calling the conversion construuctor.
Related
I cannot undestand why a copy constructor is called instead of a compile error.
I have declare two classes A B , which are independent . A is not based/derived of B. The only connection between them is that in B I use an operator that converts B to A
I have defined an operator = that gets as an argument a const reference of B.
In main I have written the following instnace of B = instance of A. I expect that a compile error will be generated. But the operator = is called
class A {};
class B {
public:
// conversion from A (constructor):
B()
{
cout << "1." << endl;
}
B(const A& x)
{
cout << "4." << endl;
}
// conversion from A (assignment):
B& operator= (const B& x)
{
cout << "3." << endl;
return *this;
}
// conversion to A (type-cast operator)
operator A() {
cout << "2." << endl;
return A();
}
};
int main()
{
A foo;
B bar; // calls constructor
bar = foo; // calls assignment
//foo = bar; // calls type-cast operator
char c;
c = getchar();
return 0;
}
I expect compile error. But the following sequence is printed
1 4 3 .
I hardly undestand how the copy constructor is called and why the operator = does not generate problem
Thank you
You have an implicit constructor
B::B(const A&)
which performs the conversion that you don't want. You can change the signature to
explicit B(const A&);
to trigger a compilation error. Note that it's good practice to mark constructors with one argument explicit by default (there is a clang-tidy check for it, too), just to avoid such conversions by accident (IMHO, it would even be better if constructors that can be constructed with a single argument would be explicit by default with the ability to make the implicit).
It's not a copy constructor that you have, it's a conversion constructor. The conversion constructor is called because you can turn a A into a B.
Do this:
explicit B(const A& x)
And now you will forbid the implicit conversion from A to B.
When you do:
bar = foo;
The compiler looks for sensible operations and allows for one conversion at most. It can use the copy assignment from B, and it knows it can create a B out of an A (because the constructor is not explicit), so it does this silently.
As #lubgr said, clang-tidy has a rule to check these and this is part of the C++ core guidelines.
I expect the following compile error will be generated
no match for 'operator=' ... note: no known conversion for argument 1 from 'A' to 'const B&'
There is no reason to expect such error, because there is a known conversion from A to const B&. B has a converting constructor for A:
B(const A& x)
The only connection between them is that in B I use an operator that converts B to A
... and the second connection between them is that in B, you use a constructor that converts A to B.
You are right that this a conversion cunstroctor. But why this called when the assignement bar = foo takes place.
Because the given operand of the assignment has the type A, while the declared argument type is const B&.
In cases where the argument type does not match the declaration, the compiler checks whether there exists an implicit conversion sequence which could be used to convert the argument. As, A is implicitly convertible to B, such implicit conversion sequence exists and will be used.
This is an overloaded operator contained in a class:
inline operator const FOO() const { return _obj_of_type_FOO; }
I cannot for the life of me understand:
How I would invoke this operator?
What would be its return value?
[Secondary] Whether making it inline affects anything apart from efficiency?
That expression looks like a declaration of a conversion operator if Foo is a type and it is inside a class. The second const (the one closer to the opening curly bracket) means that the conversion can be called on const instances. Let us say the class is C. You can think of a conversion operator as a constructor outside a class. For example, you can't add constructors to the class std::string, but you can add a conversion operator to std::string to your classes. The result is that you can construct std::string from your class instance.
1) How to invoke the conversion operator: by constructing a value of type Foo from a C, for example:
Foo foo = c (where c is an instance of C, the class that declares the conversion operator). Mind you that the invocation of the conversion can happen implicitly. If you have, for example, void funOnFoo(Foo v); and an instace c of C, this might implicitly call operator const Foo: funOnFoo(c). Whether this actually does, depends on the usual things: Whether there are other overloads of funOnFoo, other conversions for C, etc.
2) The return value is const Foo
3) inline means the same thing as for any function, in particular, does not affect overload resolution
How does constructor conversion work?
#include <iostream>
using namespace::std;
class One {
public:
One() { cout<<"One"<<endl;}
};
class Two {
public:
Two(const One&) {cout<<"Two(const One&)"<<endl;}
};
void f(Two) {cout<<"f(Two)"<<endl;}
int main() {
One one;
f(one);
}
produces the output
One
Two(const One&)
f(Two)
Any constructor that can be called with a single argument is considered an implicit conversion constructor. This includes simple 1-argument cases, and usage of default arguments.
This conversion is considered in any context that wants X and provided Y, and Y has such implicit conversion possibility. Note that a plenty of other, built-in conversions also play as a mix (like adjusting const-ness, integral and fp promotions, conversions, etc.) The rule is that at most one "user defined" implicit conversion is allowed in the mix.
In some cases it may be quite surprising, so the general advice is to make any such ctors explicit. That keyword makes the conversion possible but not implicitly: you must use T() syntax to force it.
As an example consider std::vector that has a ctor taking size_t, setting the initial size. It is explicit -- otherwise your foo(vector<double> const& ) function could be mistakenly called with foo(42).
It's right result. Since constructor is not explicit - implicit conversion works (here One is implicitly converted to Two).
one is created, then when passed to f converted to Two.
What the Two(const One&) {cout<<"Two(const One&)"<<endl;} constructor means is that you're allowed to construct a Two value at any time - implicitly - from a One. When you call f(one) it wants a Two parameter, it's given a One, so the compiler puts 2 and 2 together and says "I'll make a temporary Two from the One and complete the call to f()"... everyone will be happy. Hurray!
Compiler has to create copy of Two instance on stack. When you call f() with argument which is object of class One (or any other) compiler looks to definition of class Two and tries to find constructor which takes One(or any other) object(or reference) as an argument. When such constructor has been found it constructs object using it. It's called implicit because compiler do it without your interference.
class Foo {
public:
Foo(int number) {cout<<"Foo(int number)"<<endl;}
};
void f(Foo) {cout<<"f(Foo)"<<endl;}
int main() {
f(24);
} ///:~
Output will be:
Foo(int number)
f(Foo)
This example is from "Thinking in C++", I have one question regarding compiler synthesizing the operator conversion function.
Question
When object of class Four is passed (in the function call f()), the overload operation () is called. But I am not able to make out the logic used (compiler synthesizes the operation call) by compiler to achieve this conversion.
At max, I can expect explicit conversion behavior, like
1. obj3 = (Three)obj4;
2. obj3 = Three(obj4);
3. obj3 = static_cast<Three> (obj4);
Now for any one of the above conversion - how does the compiler synthesize,
(Three) obj4.operator()?
May be I am missing some major point.
Example
//: C12:Opconv.cpp
// Op overloading conversion
class Three {
int i;
public:
Three(int ii = 0, int = 0) : i(ii) {}
};
class Four {
int x;
public:
Four(int xx) : x(xx) {}
operator Three() const { return Three(x); }
};
void g(Three) {}
int main() {
Four four(1);
g(four);
g(1); // Calls Three(1,0)
} ///:~
First of all it is not operator() which you have provided, it is operator Three. This operator tells the compiler how to convert an object of class Four to an object of class Three. In g(four) call compiler is using this operator since the function g is expecting an argument of type Three. Since there is an conversion available compiler is using it. In the second case, since the constructor of Three is not declared as explicit and it is possible to construct a object of class Three using a single integer (using Three constructor) compiler is using that constuctor to create an object of the class Three so that function g can be called.
First of all, class Four does not contain an operator(), but it does have an operator Three(), which is a conversion operator.
In the line
g(four);
the compiler needs to convert four to an object of class Three and synthesises a call to operator Three() to perform that conversion.
The synthesised conversion is equivalent to
g(four.operator Three());
Please help me understand how exactly the conversion operators in C++ work.
I have a simple example here which I am trying to understand, though it is not very clear how the conversion actually happens by the compiler.
class Example{
public:
Example();
Example(int val);
operator unsigned int();
~Example(){}
private:
int itsVal;
};
Example::Example():itsVal(0){}
Example::Example(int val):itsVal(val){}
Example::operator unsigned int (){
return (itsVal);
}
int main(){
int theInt = 5;
Example exObject = theInt; // here
Example ctr(5);
int theInt1 = ctr; // here
return 0;
}
You can walk through that code with a debugger (and/or put a breakpoint on each of your constructors and operators) to see which of your constructors and operators is being invoked by which lines.
Because you didn't define them explicitly, the compiler also created a hidden/default copy constructor and assignment operator for your class. You can define these explicitly (as follows) if you want to use a debugger to see where/when they are being called.
Example::Example(const Example& rhs)
: itsVal(rhs.itsVal)
{}
Example& operator=(const Example& rhs)
{
if (this != &rhs)
{
this->itsVal = rhs.itsVal;
}
return *this;
}
int main() {
int theInt = 5;
/**
* Constructor "Example(int val)" in effect at the statement below.
* Same as "Example exObject(theInt);" or "Example exObject = Example(theInt);"
*/
Example exObject = theInt; // 1
Example ctr(5);
/**
* "operator unsigned int()" in effect at the statement below.
* What gets assigned is the value returned by "operator unsigned int()".
*/
int theInt1 = ctr; // 2
return 0;
}
At statement 1 the constructor Example(int val) is called. Declare it as explicit Example(int val) and you will get a compile time error i.e. no implicit conversion will then be allowed for this constructor.
All single argument constructors are called implicitly if the assigned value is of their respective argument type. Using the explicit keyword before single argument constructors disables implicit constructor calling and hence implicit conversion.
If the constructor was declared as explicit i.e. explicit Example(int val) then the following would happen for each statement.
Example exObject(theInt); // Compile time error.
Example exObject = theInt; // Compile time error.
Example exObject(Example(theInt)); // Okay!
Example exObject = Example(theInt); // Okay!
Also note that in case of implicit constructor call and hence implicit conversion the assigned value is an rvalue i.e. an un-named object implicitly created using an lvalue (theInt) which tells us that in case of implicit conversion the compiler converts
Example exObject = theInt;
to
Example exObject = Example(theInt);
So (in C++11) don't expect the lvalue constructor to be called seeing that you are using an lvalue i.e. a named value theInt for assignment. What gets called is the rvalue constructor since the assigned value is actually the un-named object created using the lvalue. However, this applies if you have both lvalue and rvalue versions of the constructor.
At statement 2 operator unsigned int() is called. Simply consider it as a normal function call with a weird name and the fact that it can get called automagically when an implicit conversion happens. The value returned by that function is the value assigned in the expression. And since in you implementation the value returned is an int it correctly gets assigned to int theInt1.
To be precise operator unsigned int() overloads () operator which is the cast operator. In your case it's overloaded for int hence whenever an object of Example class is assigned to an int the implicit type casting from Example to int takes place and hence operator unsigned int() gets called. Therefore,
int theInt1 = ctr;
is equivalent to
int theInt1 = (int)ctr;
Example exObject = theInt; // implicitly created copy constructor takes place
// object implicitly created from int and then copied
// it is like
Example exObject = Example(theInt);
// so it uses sequence
// Example(int) -> Example(const Example&)
int theInt1 = ctr; // operator int()
If you compiler supports copy constructor optimization and return value optimization you won't notice
Example(const Example&)
execution, but you can declare copy constructor to be private to understand what I am talking about.
Example exObject = theInt; // here
This uses implicit conversion of int to Example, effected by the non-explicit constructor which accepts an int.
This also requires the availability of copy constructor for Example, even though the compiler is allowed to omit copying the instance.
int theInt1 = ctr; // here
This uses implicit conversion of Example to unsigned int, provided by the cast operator.
Cast operators are normally avoided, since they tend to lead to confusing code, and you can mark single-argument constructors explicit, to disable implicit conversions to your class type. C++0x should add also the possibility to mark conversion operators explicit (so you'd need a static_cast to invoke them? - my compiler doesn't support them and all web resources seem to be concentrating on explicit conversion to bool).