struct A {
int i;
};
struct B {
A a;
operator A*() { return &a; }
};
int main(int argc, char *argv[])
{
B b;
return b->i;
}
g++ reports error: base operand of ‘->’ has non-pointer type ‘B’
Why? I've figured out how to circumvent this problem (using operator->), but I don't understand why implicit conversion doesn't take place.
This is a consequence of how overload resolution is defined for the -> operator. Quoting from C++14 [over.match.oper]/3:
For the operator ,, the unary operator &, or the operator ->, the built-in candidates set is empty.
That is, if the left side operand of -> is of class or enumeration type, then the -> will never have its built-in meaning; instead, name lookup for operator-> as a member of the left side operand's class must succeed.
If the built-in -> operator were a candidate, then the compiler could consider implicit conversions that would allow B to be converted to a type that the built-in -> could take, but it is not a candidate, so that doesn't happen.
Because C++ will only implicitly convert a class instance when it knows what it should convert to. If you use expressions like b->, it can't know what pointer type (if any) you would want to convert it to, and will just use the normal operators (which are not defined unless overloaded):
B b;
// calls B::operator-> since that's what you tell it to do
b->i;
// calls B::operator A* since it knows it's implicitly converting to A*
A *a = b;
If you want to use the first expression here, the correct way is to overload operator->:
class B {
/* ... */
A* operator ->() { return &a; }
}
but I don't understand why implicit conversion doesn't take place.
There's no context for it to take place in. operator-> applies implicitly to pointers, or to class types with that operator defined. But that's it. There's no other sequence through which the compiler will look to find it. In this case, the built-in candidate set for b-> is empty, there is no operator->, hence compile error.
You just want to add:
A* operator->() { return &a; }
Related
Consider this snippet of C++ code:
struct Foo {
float value;
operator float& () {
return this->value;
}
};
int main() {
Foo foo;
foo=1.0f; //Doesn't compile, foo isn't implicitly converted to a float&
return 0;
}
Why doesn't this compile? Is there a specific reason this wasn't included in the C++ standard? Or an equivalent does indeed exist and I'm just using it wrong?
For pretty much all other operators, your conversion operator would do exactly what you want, and it would continue to do exactly what you want even if you add custom operators.
struct Foo {
float value;
operator float& () { return this->value; }
Foo &operator+=(Foo);
};
int main() {
Foo foo {};
foo+=1.0; // compiles and works
// equivalent to foo.operator float&()+=1.0;
}
However, = is special, the rules for = are different compared to most other operators. As identified by T.C.:
13.3.1.2 Operators in expressions [over.match.oper]
4 For the built-in assignment operators, conversions of the left operand are restricted as follows:
(4.1) -- no temporaries are introduced to hold the left operand, and
(4.2) -- no user-defined conversions are applied to the left operand to achieve a type match with the left-most parameter of a built-in candidate.
Together with the fact that any custom operator= is not allowed to be defined as a global function, this makes sure that foo=bar; where foo is a class type always means foo.operator=(bar);, nothing else.
The fact that this one operator is singled out doesn't explain the reason, but does make it quite clear that it's an intentional decision, and making sure that foo=bar; always means foo.operator=(bar);, nothing else, by itself already seems like a valid reason.
Implicit conversion is only done in the following cases:
Implicit conversions are performed whenever an expression of some type
T1 is used in context that does not accept that type, but accepts some
other type T2; in particular:
when the expression is used as the argument when calling a function that is declared with T2 as parameter;
when the expression is used as an operand with an operator that expects T2;
when initializing a new object of type T2, including return statement in a function returning T2;
when the expression is used in a switch statement (T2 is integral type);
when the expression is used in an if statement or a loop (T2 is bool).
None of those is the case here. Instead the compiler is trying to find a suitable operator= to work with a double. To have this compile you need to overload that operator ( you actually want a float as seen in the code ):
Foo& operator=(float other)
{
value = f;
return *this;
}
And change your assignment to foo = 1.0f;
Your conversion function would work with for example:
float f = foo;
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
Is it possible to override (C-style) casts in C++?
Suppose I have the code
double x = 42;
int k = (int)x;
Can I make the cast in the second line execute some code I wrote? Something like
// I don't know C++
// I have no idea if this has more syntax errors than words
operator (int)(double) {
std::cout << "casting from double to int" << std::endl;
}
The reason I ask is because of the question "Is there any way to get gcc or clang to warn on explicit casts?" and my suggestion there.
§ 12.3.1/1 "Type conversions of class objects can be specified by constructors and by conversion functions. These conversions are called user-defined conversions and are used for implicit type conversions (Clause 4), for initialization (8.5), and for explicit type conversions (5.4, 5.2.9)."
Yes, we can make conversions, but only if one or both sides is a user-defined type, so we can't make one for double to int.
struct demostruct {
demostruct(int x) :data(x) {} //used for conversions from int to demostruct
operator int() {return data;} //used for conversions from demostruct to int
int data;
};
int main(int argc, char** argv) {
demostruct ds = argc; //conversion from int to demostruct
return ds; //conversion from demostruct to int
}
As Robᵩ pointed out, you can add the explicit keyword to either of those conversion functions, which requires the user to explicitly cast them with a (demostruct)argc or (int)ds like in your code, instead of having them implicitly convert. If you convert to and from the same type, it's usually best to have one or both as explicit, otherwise you might get compilation errors.
Yes, but only for your own types. Look at this:
#include <iostream>
struct D {
// "explicit" keyword requires C++11
explicit operator int() { std::cout << __FUNCTION__ << "\n"; }
};
int main () {
int i;
D d;
//i = d;
i = (int)d;
}
So, you cannot create double::operator int(), but you could create MyDouble::operator int().
You can’t overload operators for built-in types, but you can write a conversion operator for a user-defined type:
struct Double {
double value;
operator int() const {
shenanigans();
return value;
}
};
Since your question arose from a need to find explicit casts in code, also be aware that C++ has explicit casting operators. These are not only clearer than C-style casts, but also eminently searchable:
static_cast<T>(x) // Cast based on static type conversion.
dynamic_cast<T>(x) // Cast based on runtime type information.
const_cast<T>(x) // Add or remove const or volatile qualification.
reinterpret_cast<T>(x) // Cast between unrelated pointer and integral types.
Conversions to other types are overloadable operators in C++ (some examples here), but this fact will not help you.
Stroustrup wanted the language to be extensible, but not mutable. Therefore, overloading an operator only extends the operations to new types, but you cannot redefine what happens with any old types.
"However, to avoid absurdities, it is (still) not allowed to provide new meanings for the built-in operators for built-in types. Thus, the language remains extensible but not mutable."
class Test
{
public:
operator Test * () { return NULL; };
};
int main()
{
Test test;
if (test == NULL)
printf("Wtf happened here?\n");
return 0;
}
How is it that this code compiles? How did Test get a comparison operator? Is there some implicit casting going around? What does that overloaded operator even mean (and do)?
The overloaded operator adds a conversion from Test to Test *. Since there is no comparision operator defined that takes Test and NULL as arguments, any conversion operators that exists are tried. operator Test * returns a type which is comparable with NULL, so it is used.
Yes, you've added an implicit conversion to T*, so the compiler will use it to compare against NULL.
A few other things to note:
NULL is shorthand for 0, so this means that comparison against 0 will be allowed. (This isn't true for other integer values, however. 0 is special.)
Your type also can be implicitly used in boolean contexts. That is, this is legal:
Test test;
if (test)
{
// ...
}
C++0x allows you to specify an explicit keyword for conversion operators to disallow this sort of thing.
Implicit conversion to pointer types is often pretty dubious. In addition to the pitfalls of the conversion happening in unexpected cases, it can allow dangerous situations if the object owns the returned pointer. For example, consider a string class that allowed implicit conversion to const char*:
BadString ReturnAString();
int main()
{
const char* s = ReturnAString();
// Uh-oh. s is now pointing to freed memory.
// ...
}
+1 for Baffe's response. If you're looking to somehow expose some instance of a wrapped object via * then perhaps you should overload -> instead of overloading *.
class Bar
{
public:
void Baz() { ... }
}
class Foo
{
private:
Bar* _bar;
public:
Bar* operator -> () { return _bar; }
}
// call like this:
Foo f;
f->Baz();
Just a thought.
You have not defined your own comparison thus he compiler has done one for you. you have however tried to overload the dereference operator... which I can't see why.
you want to define your operator== function
read this
C++ does not allow polymorphism for methods based on their return type. However, when overloading an implicit conversion member function this seems possible.
Does anyone know why? I thought operators are handled like methods internally.
Edit: Here's an example:
struct func {
operator string() { return "1";}
operator int() { return 2; }
};
int main( ) {
int x = func(); // calls int version
string y = func(); // calls string version
double d = func(); // calls int version
cout << func() << endl; // calls int version
}
Conversion operators are not really considered different overloads and they are not called based on their return type. The compiler will only use them when it has to (when the type is incompatible and should be converted) or when explicitly asked to use one of them with a cast operator.
Semantically, what your code is doing is to declare several different type conversion operators and not overloads of a single operator.
That's not return type. That's type conversion.
Consider: func() creates an object of type func. There is no ambiguity as to what method (constructor) will be invoked.
The only question which remains is if it is possible to cast it to the desired types. You provided the compiler with appropriate conversion, so it is happy.
There isn't really a technical reason to prevent overloading of functions on the result types. This is done in some languages like Ada for instance, but in the context of C++ which has also implicit conversions (and two kind of them), the utility is reduced, and the interactions of both features would quickly leads to ambiguities.
Note that you can use the fact that implicit conversions are user definable to simulate overloading on result type:
class CallFProxy;
CallFProxy f(int);
class CallFProxy {
int myParameter;
CallFProxy(int i) : myParameter(i) {}
public:
operator double() { std::cout << "Calling f(int)->double\n"; return myParameter; }
operator string() { std::cout << "Calling f(int)->string\n"; return "dummy"; }
};
Overload resolution chooses between multiple candidate functions. In this process, the return type of candidates is indeed not considered. However, in the case of conversion operators the "return type" is critically important in determining whether that operator is a candidate at all.