I was trying to implement a smart pointer class similar to the standard library auto_ptr and accordingly I had to overload the -> operator for the same. Here is my code
template <typename T>
class SmartPtr
{
T * operator -> ()
{
return _pAct;
}
private:
T * _pAct;
};
Rest of the implementation is not shown so as to avoid diversion from my query.
Now I create a SmartPtr of class A and call a method Show() present in A on it :
SmartPtr smPtr(new A);
smPtr->Show();
Here is my query(don't know if its valid also)
Since SmartPtr::operator->() return A*, the call to show should translate to (A*)Show. Why it translates to (A*)->Show() ?
or in other words how does smPtr->Show() mean call Show() on whatever smPtr->() operator returns ?
Because operator -> applies sequentially until it can't be applied any more.
13.5.6 Class member access [over.ref]
1) operator-> shall be a non-static member function taking no
parameters. It implements class member access using ->
postfix-expression -> id-expression An expression x->m is interpreted
as (x.operator->())->m for a class object x of type T if
T::operator->() exists and if the operator is selected as the best
match function by the overload resolution mechanism (13.3). (emphasis mine)
Which means, in your case, it translates to:
smPtr.operator->()->Show();
| |
returns A* call Show on the A*
Related
Consider the following code:
class Foo
{
public:
//class-specific
Foo operator+(Foo& rhs)
{
return Foo(); //Just return a temporary
}
void* operator new(size_t sd)
{
return malloc(sd);
}
};
//global
Foo operator+(Foo& lhs, Foo& rhs)
{
return Foo();
}
void* operator new(size_t sd)
{
return malloc(sd);
}
This code will not compile, stating the call is ambiguous because it matches two operators:
Foo a, b;
a + b;
But this one with the new operator compiles just fine, and will call the class-specific one.
Foo* a = new Foo();
Why doesn't it result in a compile error? Does the compiler treat the new operator differently? (Any citation to the standard would be appreciated.)
Why doesn't it result in a compile error? Does the compiler treat the new operator differently? (Any citation to the standard would be appreciated)
Regarding the precedence between global new and class specific new, the reference says this:
As described in allocation function, the C++ program may provide global and class-specific replacements for these functions. If the new-expression begins with the optional :: operator, as in ::new T or ::new T[n], class-specific replacements will be ignored (the function is looked up in global scope). Otherwise, if T is a class type, lookup begins in the class scope of T.
So class specific new has priority.
Regarding the overload of +, you can either have the member overload or the global overload (usually as a friend of the class) but not both because of the ambiguity it produces.
The class' operator new is always preferred if defined:
[expr.new]/9
If the new-expression begins with a unary :: operator, the allocation function's name is looked up in the global scope. Otherwise, if the allocated type is a class type T or array thereof, the allocation function's name is looked up in the scope of T. If this lookup fails to find the name, or if the allocated type is not a class type, the allocation function's name is looked up in the global scope.
It can be tricky to read: if the new-expression does not begins with :: and the allocated type is a class type, then new is looked up in the class' scope.
Your global new operator has no direct relation to the class Foo. A class specific new has precedence over the global new. There is no ambiguity.
Your operator+ does specifically relate to the class Foo. There is no precedence between the operator defined outside and the one defined inside the class. Thus you get ambiguity.
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
This question gives a good answer why to define operator overloads as non-members: Operator overloading : member function vs. non-member function?
If you define your operator overloaded function as member function,
then compiler translates expressions like s1 + s2 into
s1.operator+(s2). That means, the operator overloaded member function
gets invoked on the first operand. That is how member functions work!
But what if the first operand is not a class? There's a major problem
if we want to overload an operator where the first operand is not a
class type, rather say double. So you cannot write like this 10.0 +
s2. However, you can write operator overloaded member function for
expressions like s1 + 10.0.
Now I have a situation where I need to overload operator==. In my case, only (a) objects of (b) the same type will be compared.
Is there a reason to still define operator== as a non-member or should I implement it as a member in that case?
Because operator== has symmetric semantics for its LHS and RHS argument, the recommended approach is to always implement it as a non-member in terms of the public interface of its operands (or if private data is required, to declare it as a friend inside the class).
So
class Bla
{
public:
// complete interface to data required for comparison
auto first();
auto second();
// ... more
private:
// data goes here
};
bool operator==(Bla const& L, Bla const& R)
{
return
std::forward_as_tuple(L.first(), L.second() /*, ... */) ==
std::forward_as_tuple(R.first(), R.second() /*, ... */)
;
}
This way, implicit conversion to Bla are considered for both the L and R arguments (I'm not saying implicit conversions are a good idea, but if you have those, it's better to avoid surprises where they are only considered for the RHS argument).
I have a class, let's call it Wrapper, that wraps a given type, let's say MyClass.
In reality, Wrapper is a class template, but I think that's not relevant here.
Wrapper exposes the wrapped MyClass by means of a conversion operator (just for reading).
When I create an operator for MyClass as free function (in my example a unary minus operator), this works as expected, I can use the operator also on the Wrapper class.
If I, however, implement the operator as a member function, the compiler complains: error: no match for ‘operator-’.
I thought the free function and the member function are equivalent in this case, why aren't they?
Is there a way to change the Wrapper class that a member operator or MyClass works?
If there isn't, does this suggest that it is in general preferable to implement an operator as free function instead of as member function?
Here's some code to illustrate the problem.
struct MyClass {
// This doesn't work:
void operator-() const {}
};
// It works with this instead of the member operator:
//void operator-(const MyClass&) {}
struct Wrapper {
operator MyClass() const { return MyClass(); }
};
int main() {
-Wrapper();
}
Here's a live example: http://ideone.com/nY6JzR
Question I thought the free function and the member function are equivalent in this case, why aren't they?
Answer
In order for -Wrapper() to work correctly, the compiler has to perform a lookup for operator-. It looks for the name operator- in the default namespace, in the class Wrapper, and the namespace where Wrapper is defined. It doesn't look at other classes and namespaces for the name.
That explains the compiler error when the operator-() is moved to MyClass and why it succeeds when it is defined as a non-member function.
Question Is there a way to change the Wrapper class that a member operator or MyClass works?
Answer There are two ways to resolve this.
Make the operator functions for MyClass non-member functions.
Create operator functions in MyClass as well as Wrapper, with the implementations in Wrapper being simple pass through functions. The good thing about this is that then you don't have to care whether the operator functions in MyClass are member functions or non-member functions.
Question If there isn't, does this suggest that it is in general preferable to implement an operator as free function instead of as member function?
Answer This can be a policy decision based on the choice you make to the previous answer.
I thought the free function and the member function are equivalent in
this case, why aren't they?
Lets see what happens when a conversion operator is used.
Essentially, there is a global operator function, which has a parameter of type MyClass. Now, since Wrapper has a conversion operator, the call operator-( Wrapper() ) will be inspected by overload resolution to find the best match - and overload resolution finds that there is a global operator function with parameter MyClass const& (or similiar). Then it tries to convert the Wrapper prvalue to MyClass const& and sees that there is a user-defined conversion sequence: One that uses the conversion operator to convert the Wrapper-object to a MyClass object, which then can be used to (copy-)initialize the reference.
If the operator function is a member instead, there is a problem: A global function call of the form operator-( Wrapper() ) does obviously not yield any viable functions. But the one that assumes the operator function is a member doesn't yield anything either - because operator- is not a member of Wrapper, therefore Wrapper().operator-() doesn't work and doesn't yield any viable functions either.
Remember: A class with a conversion operator does not inherit the members of the target type. If you wanted that, you should have inherited MyClass.
For a unary operator # with an operand of a type whose cv-unqualified
version is T1 [...] three sets of candidate functions, designated
member candidates, non-member candidates and built-in candidates, are
constructed as follows:
If T1 is a complete class type, the set of member candidates is the
result of the qualified lookup of T1::operator# (13.3.1.1.1);
otherwise, the set of member candidates is empty.
The set of non-member candidates is the result of the unqualified lookup of
operator# in the context of the expression according to the usual
rules for name lookup in unqualified function calls (3.4.2) except
that all member functions are ignored. [...]
I am working on some code where there is a simple enum in a class. A different piece of code has a pointer to that class and is accessing a value of the enum through the arrow pointer.
How on earth is the class able to access MY_VALUE1 this way?
I though it would only allow access via MyClass::MY_VALUE1 or MyClass::MyEnum::MY_VALUE1.
class MyClass {
public:
enum MyEnum{
MY_VALUE0 = 0,
MY_VALUE1 = 1
};
//getters, setters as appropriate
};
//Other class
MyClass* myClass = new MyClass();
//Compiles without C++11
if(getRandomEnum() == myClass->MY_VALUE1)
{
//Do Stuff
}
The -> operator is (mostly) an abbreviation for dereference (*) and selection (.). In other words, a->b is the same as (*(a)).b. (§5.2.5/2; See notes below).
The . syntax is class member access, as defined by §5.2.5 [expr.ref]; the identifier on the right-hand side of the . can be a static or non-static data member, function, or member enumerator (paragraph 4 of the cited section). It cannot be a nested type. In this sense, member enumerators are syntactically similar to static const data members.
Notes:
As §13.5.6 clarifies, a->b is is subject to operator overloading. If a is not a pointer type, then -> may be overloaded, in which case the expression is interpreted as (a.operator->())->b. Eventually, the sequence of overloaded -> calls must result in a pointer type, at which point the interpretation of §5.2.5/2 is applied.
An important difference between Class::member and value.member is that in the second case, value will be evaluated even if that is unnecessary to resolve the value of member.
From C++ ISO/IEC 2011
An enumerator declared in class scope can be referred to using the
class member access operators (::, . (dot) and -> (arrow)),
The enum values are treated much as if they were static members
of the class, and can be accessed in two ways: via the class
name followed by the scope resolution operator
(MyClass::MY_VALUE0), or like any other member
(instance.MY_VALUE0 or pointer->MY_VALUE0).
Note that in the latter case, the operand on the left is still
evaluated, even though the results of the evaluation is not
used. In other words, if I write f()->MY_VALUE0 (where f()
returns a MyClass*), the function will be called, despite the
fact that its return value is not used.