I don't understand what is going on in the following piece of code:
struct A { };
struct B {
B() { }
B(const A&) { }
friend B operator*(const B&, const B&)
{
return B();
}
};
int main()
{
B x = A() * A();
return 0;
}
When I compile (with both clang and gcc 4.9.2) I get an error message on the "B x = A() * A()" line; clang says "invalid operands to binary expression".
If I take the operator* definition from inside the class, everything is 100% ok!
struct A { };
struct B {
B() { }
B(const A&) { }
friend B operator*(const B&, const B&);
};
B operator*(const B&, const B&)
{
return B();
}
int main()
{
B x = A() * A();
return 0;
}
What is going on?
Since operator*() is defined inside the function as a friend, it can only be found by ADL, not normal unqualified lookup. This type of lookup requires that the arguments be exact types, not types that are implicitly convertible. This means the operator cannot be found even if A can be converted to B.
When you declare the function outside the class, then it can be found by the normal unqualified lookup rules.
Related
in the below code (which is an example for type conversion):
// implicit conversion of classes:
#include <iostream>
using namespace std;
class A {};
class B {
public:
// conversion from A (constructor):
B (const A& x) {}
// conversion from A (assignment):
B& operator= (const A& x) {return *this;}
// conversion to A (type-cast operator)
operator A() {return A();}
};
int main ()
{
A foo;
B bar = foo; // calls constructor
bar = foo; // calls assignment
foo = bar; // calls type-cast operator
return 0;
}
in line 21:
bar = foo; // calls assignment
it calls the overloaded operator =. and in the body of class overloading for "=" operator is written in line 12:
B& operator= (const A& x) {return *this;}
it's statement says "return this". here this points to bar. and there's just a parameter of type class A:
const A& x
what does this function do with this parameter?
and in line 21 what is converted to what by writing:
bar = foo; ?
The real question you might be asking is what does the operator= function used for?
Normally we take some data from the constant reference
For example
struct A{
std::string data;
}
struct B{
std::string differentData;
B& operator=(const A& other){
differentData = other.data;
return *this;
}
}
Then if we call code like
int main(){
A a;
a.data = "hello";
B b;
b = a;
std::cout << b.differentData;
}
We should get "hello" printing to the console
Since you're not interacting with the class given in the function, all this code is doing is running an empty function.
The return is only used if you chain together equal calls
int main(){
B b1, b2, b3;
b3.differentData = "hi";
b1 = b2 = b3;
//Pushes hi from b3 >> b2 and returns b2
//Pushes hi from b2 >> b1 and returns b1
}
what does this function do with this parameter?
Nothing.
what is converted to what by writing: bar = foo;
Nothing. Or equivalently, the state of bar is replaced from the state of foo.
I am refactoring our code-base, where I have the following code (simplified):
template <typename T>
class TVector3;
template <typename T>
class TVector4;
template <typename T>
struct TVector4
{
TVector3<T>& V3() { return (TVector3<T> &) *this; }
const TVector3<T>& V3() const { return (const TVector3<T> &) *this; }
};
template <typename T>
struct TVector3
{
template <typename U>
constexpr TVector3(const TVector4<U>& v) noexcept { }
};
typedef TVector3<float> Vec3f;
typedef TVector4<float> Vec4f;
struct RGBA
{
Vec4f rgba;
operator Vec3f() const { return rgba.V3(); }
};
clang warns me about returning reference to local temporary object (https://godbolt.org/z/ccxbjv771). Apparently (const TVector3<T> &) *this results in calling TVector3(const TVector4<U>& ), but why ?
Intuitively, I would have expected (const TVector3<T> &) to behave like reinterpret cast, or if at least the cast would have looked like (const TVector3<T>) *this (without &) it would kind of make sense to me that the compiler picked that constructor call for conversion.
Another simpler example:
#include <iostream>
struct A { };
struct B
{
B(const A& ) { std::cout << "B(const A&)" << std::endl; }
};
int main()
{
A a;
(const B&) a;
return 0;
}
It prints B(const A&) (https://godbolt.org/z/ocWjh1eb3), but why ? I am converting to const B& and not to B.
It calls the constructor because such are the rules of c-style cast:
cppreference: When the C-style cast expression is encountered, the compiler attempts to interpret it as the following cast expressions, in this order:
a) const_cast<new_type>(expression);
b) static_cast<new_type>(expression), with extensions: pointer or reference to a derived class is additionally allowed to be cast to pointer or reference to unambiguous base class (and vice versa) even if the base class is inaccessible (that is, this cast ignores the private inheritance specifier). Same applies to casting pointer to member to pointer to member of unambiguous non-virtual base;
c) static_cast (with extensions) followed by const_cast;
d) reinterpret_cast<new_type>(expression);
e) reinterpret_cast followed by const_cast.
The first choice that satisfies the requirements of the respective cast operator is selected, even if it cannot be compiled (see example). If the cast can be interpreted in more than one way as static_cast followed by a const_cast, it cannot be compiled.
static_cast is chosen because it considers the constructors. Please do not use c-style cast, you see the rules are not so easy and it forced you to make a question about them.
Intuitively, I would have expected (const TVector3 &) to behave like reinterpret cast
You wouldn't want that, it would break strict aliasing. But if you remove the constructor, it will happily do that as per d).
#include <iostream>
struct A { };
struct B
{
B(const A& ) { std::cout << "B(const A&)" << std::endl; }
};
struct C
{
};
int main()
{
A a;
const B& temp1 = (B&) a;// Ctor, copy, prolonged-life good.
const B& temp2 = (const B&) a;// Ctor, copy, prolonged-life good.
B& dangling_temp = (B&) a;// Ctor, copy, no prolongment->dangling ref, BAD.
(const C&) a;// REINTERPET_CAST
//(const C) a;// Compiler error, good.
(const C*) &a;// REINTERPET_CAST
return 0;
}
But a is not a B? If you really really want it to be B, use reinterpret_cast(but don't) or bit_cast explicitly. The sane thing is to attempt to make a copy if possible. It creates a new temporary B and binds it to const B&. Had you stored it into const B& b, it would prolong the temporary's lifetime, making the code safe.
It prints B(const A&), but why ? I am converting to const B& and not to B.
The type of a is A, it can't be bound to const B& directly. It needs to be converted to B via B::B(const A& ) firstly; then the converted temporary B is bound to const B&. (Lvalue-reference to const could bind to temporaries.)
I can't understand why a.funct() can be the left operand of the assignment operator even if funct() is not returning a l-value reference.
class A
{
public:
A funct () {A x; return x;}
};
int main ()
{
A a,b; a.funct()=b;
}
In the auto generated methods for the class, there is
A& operator = (const A&);
which make a.funct() = b legal.
To forbid affectation to rvalue, you may, since C++11, write and implement
A& operator = (const A&) &; // Note the last &
so assignation would only work for lvalue.
In the code, funct should return a variable that can be assigned to.
Note that the code in funct is very dangerous too if it were to be returned by reference; the local variable x will go out of scope once the function ends and the variable returned will cause undefined behaviour as its destructor will have been called.
Your assumption is wrong. Your code is perfectly valid.
Try this code:
#include <string>
#include <iostream>
class A
{
std::string m_name;
public:
A(const std::string& name) :m_name(name) {}
A funct() { A x("intern"); return x; }
A& operator=(const A& a)
{
m_name += a.m_name;
return *this;
}
void print() { std::cout << m_name << std::endl; }
};
int main()
{
A a("A"), b("B"); (a.funct() = b).print();//prints "internB"
}
It was very hard to come up with a title... (I'm not a native English speaker.)
struct A
{
int value;
A operator+(int i) const
{
A a;
a.value=value+i;
return a;
};
};
int main(){
A a;
a.value=2;
a=a+2;
return 0;
}
This code compiles/works as expected, but when I change a=a+2 to a=2+a, it won't compile anymore.
GCC gives me this error:
no match for ”operator+” in ”2 + a”
Is there any way to somehow make 2+a work just like a+2?
You need a free function, defined after the class
struct A
{
// ...
};
A operator+(int i, const A& a)
{
return a+i; // assuming commutativity
};
also, you might consider defining A& operator+=(int i); in A an implement both versions of operator+ as free functions. You might also be interested in Boost.Operators or other helpers to simplify A, see my profile for two options.
Sure, define the inverse operator outside the class:
struct A
{
int value;
A operator+(int i) const
{
A a;
a.value=value+i;
return a;
};
};
//marked inline to prevent a multiple definition
inline A operator+(int i, const A& a)
{
return a + i;
}
The other answers here work fine. However, another option you have is to create a constructor for a single int like this:
struct A
{
int value;
A(int i) {
value = i;
}
};
This allows integers to get implicitly converted, and allows you to only overload operators for your struct instead:
A operator+(const A& other) const
{
// All you need to do is work with an A, and associativity works fine
};
Of course, this does allow all integers to get implicitly converted to As, which may or may not be desirable.
I encountered this code but I could not understand the functionality of this code.
It would be a great help if someone could explain it .
struct A{
int i,j;
A(int ii,int jj) : i(ii),j(ii){}
A(const A&a){
}
A& operator =(const A& a){
i=a.i;j=a.j;
}
};
int main()
{
int i;
A a(1,2);
A b(2,3);
A z = (a=b);
cout<<z.i<<" "<<z.j<<endl;
system("pause");
return 0;
}
Explanation:
struct A{
int i,j;//members i and j
A(int ii,int jj) : i(ii),j(ii){} //A constructor. Short form of A(int ii,int jj){i = ii;j = jj;} Original code is wrong too. Should be j(jj) instead of j(ii)
A(const A&a){}//Another constructor. It is missing the assignment
A& operator =(const A& a){
i=a.i;j=a.j;
}//Equal operator overload definition for A = another A. It copies the data from another A and assign to this new one
};
Complete working code:
#include <iostream>
using namespace std;
struct A{
int i,j;
A(int ii,int jj) : i(ii),j(jj){}
A(const A&a){i=a.i;j=a.j;}
A& operator =(const A& a){i=a.i;j=a.j;}
};
int main()
{
int i;
A a(1,2);
A b(2,3);
A z = (a=b);
cout<<z.i<<" "<<z.j<<endl;
return 0;
}
Your problem is this line:
A z = (a=b);
It ends up invoking both your operator= method and your Copy Constructor. When a = b is executed, it uses the operator= method because a already exists and then a reference to a is returned. You're essentially calling a.operator=(b).
When A z = ... is executed, it actually uses the Copy Constructor A(const A&a), not the operator= method because z does not exist yet. Since z is being created by that copy constructor and i and j are never initialized, when you try to print them out, you get whatever junk was located in the memory reserved for i and j.
Another way to view this line:
A z = (a=b);
Is actually like this:
A z(a.operator=(b));
Here's a full example:
int main()
{
A a(1,2);
A b(2,3);
a = b; //calls A& operator=(const A& a)
A z = a; //calls A(const A& a)
}
In conclusion, the fix is to do this:
A(const A& a)
{
i = a.i;
j = a.j;
}
Three mistakes:
1.A(int ii,int jj) : i(ii),j(ii /* jj here? */){}
2.The copy constructor should initialize the members: A(const A&a): i(a.i), j(a.j) {}
3.You should Add return *this in operator=:
A& operator =(const A& a){
i=a.i;j=a.j;
return *this;
}
The OP has asked the operator overloadin part. if we take a as const how can we edit it.
The operator overloading part is:
A& operator =(const A& a){
i=a.i;j=a.j;
}
When you write a=b, you only expect a to change and not b. This is enforced by the const specifier in the function argument definition. This const specifier has nothing to do with whatever appears on the left hand side of the equal sign. It only says that the right hand side of the equal sign will not be modified.