I can overload the parenthesis operator using the following signature:
char& operator()(const int r, const int c);
The intended usage of this would be:
// myObj is an object of type MyClass
myObj(2,3) = 'X'
char Y = myObj(2,3);
Which works as I expect. However, using the parenthesis operator when dealing with a pointer becomes convoluted. I would like to do:
// pMyObj is a pointer to an object of type MyClass
pMyObj->(2,3) = 'X';
char Y = pMyObj->(2,3);
However, such syntax yields the error Error: expected a member name (in VisualStudio at least).
The following does work but seems convoluted to me with a dereference and more parentheses than arguments.
char X = (*pMyObj)(2,3);
Is there a way to use the -> operator to call the () overload?
Yes there is, but you won't like it:
pMyObj->operator()(2,3);
You could also create a reference to the pointed to object and do
MyObj& rMyObj = *pMyObj;
char Y = rMyObj(2, 3);
which might be a good alternative if your code will be read by people who could be confused by
pMyObj->operator()(2,3);
if you do as below
#define SUB operator()
Then you can write things like this ...
pMyObj->SUB(2,3)
not as elegant as Fortran ;-) but perhaps not too ugly for actual use
Related
I have an unordered map that uses a pointer to a custom object as key.
For some reason looking up the values with the key only works if the key is not const.
Here is an example (with std::string as stand-in for the custom object):
std::unordered_map<std::string*, int> my_map;
std::string key {"test"};
const std::string const_key {"test2"};
auto value = my_map.at(&key); // this works as expected
auto other_value = my_map.at(&const_key); // this doesn't compile
error: invalid conversion from 'const string* {aka const std::__cxx11::basic_string<char>*}'
to 'std::unordered_map<std::__cxx11::basic_string<char>*, int>::key_type
{aka std::__cxx11::basic_string<char>*}' [-fpermissive]
Why would a lookup require the pointer to be non const?
When you write &const_key this evaluates to const std::string *, but your map uses std::string * as key type.
There is a difference between "address to string" and "address to a string that is const". Therefore these are considered different types, and you cannot use them interchangeably.
P.S. Could not write this as comment, so posted as answer.
thought I would offer a little more reasoning as to why this is going on (I ran into the same problem... grumble grumble grumble).
Consider the following code:
template <typename T>
void f(T t) { *t += 1; }
int main() {
const int x = 0;
//f<int*>(&x); //error: no matching function for call to ‘f<int*>(const int*)’
//f(&x); //error: assignment of read-only location ‘* t’
int y = 0;
f<int*>(&y); //okay, what we're "supposed" to do
int * const z_p = &y;
f(z_p); //okay, we'll copy z_p by value and modify y
}
In this (somewhat minimal) example, we can clearly see why we can't take a const int * as an argument to our function f(int *). If we did, we could modify it (not good). This covers the no matching function call, but in the second case we get through the template deduction with no problems, but hit a wall when we try to modify our value (that's not the template functions fault, you are using it wrong!) The third case is boring and expected, and I threw in the fourth case just to remind those of you who, like me, get confused with funny pointer types.
If you are sure of that the function you are calling won't modify your thing, or you are an international man of mystery, then there is always the option to cast your pointer.
f<int*>((int*)&x); //that's just lazy
f<int*>(const_cast<int*>(&x)); //that's just crazy
In this specific example, the results of the code above are undefined. I ran it on my machine with g++ --std=c++14 -g -O0 -Wall and got about what I expected, the value of x didn't change a bit. Today we were playing around with this situation and found that because this is undefined behavior, the compiler is allowed to optimize out the const value read from the object code. Note that x still exists on the stack, and you can modify that place in memory like you would any other, but when you read it the initial value will likely just be given by the compiler. Finally, if you move the definition of x to global scope, then you may very well have a segfault if you cast away the const-ness and modify the location in memory.
In general, I find the confusion somewhat justified, because the std::unordered_map<Key,T>::value_type is std::pair<const Key, T> (https://en.cppreference.com/w/cpp/container/unordered_map). In my mind I sort of thought "oh, then I can just shove a const whatever in there and it'll all work out." Then I found this post and scratched my head for a second, thought of the above example, and once again found that the language is protecting me from my funny self. Sigh...
For more reading on the matter, see: https://en.cppreference.com/w/cpp/language/template_argument_deduction.
The map is declared like
std::unordered_map<std::string*, int> my_map;
^^^^^^^^^^^^
You are truing to call the method at with a key of type const std::string *
auto other_value = my_map.at(&const_key);
^^^^^^^^^^
There is no implicit conversion from the type const std::string * to the type std::string *.
You could for example declare the map like
std::unordered_map<const std::string *, int> my_map;
and in this case both arguments std::string * and const std::string * could be used.
I have been recently learning how to use the std::mem_fn library facility. In C++ Primer 5th edition they give an example of a usage of std::mem_fn, in the following code snippet svec is a vector of strings:
auto f = mem_fn(&string::empty); // f takes a string or a string*
f(*svec.begin()); // ok: passes a string object; f uses .* to call empty
f(&svec[0]); // ok: passes a pointer to string; f uses .-> to call empty
Note: In the above code snippet there is no use of ->*
Although I understand the usage .* and ->*. I don't have clarity on it.
So, My question is what does .*, ->*, .-> do?
You have an object o and a pointer to its member m. The operator .* allows you to access the pointed member of your object:
o.*m
You have a pointer to an object p and a pointer to its member m. The operator ->* allows you to access the pointed member of the pointed object:
p->*m
I am afraid that the operator .-> doesn't exist.
Operators .* and ->* call a member function (BTW there is no meaning for .-> in C++ - it's a syntax error).
These are binary operators. The left operand is an object (for .*) or a pointer to an object (for ->*), and the right operand is a pointer to a member (which can be a member field or a member function). The outcome of applying this operator is the ability to use a member field or a method.
Maybe these operators make sense from a historical point of view. Suppose you use a regular C pointer to a function:
typedef int (*CalcResult)(int x, int y, int z);
CalcResult my_calc_func = &CalcResult42;
...
int result = my_calc_func(11, 22, 33);
What if you decided to "rewrite" your program in an object-oriented way? Your calculation function would be a method in a class. To make a pointer to it, you need a new type, a pointer to member function:
typedef int (MyClass::*CalcResult)(int x, int y, int z);
CalcResult my_calc_func = &MyClass::CalcResult42;
...
MyClass my_object;
int result = (my_object.*my_calc_func)(11, 22, 33);
I always use this analogy when I try to remember the syntax of this .* operator - this helps because the regular pointer-to-function syntax is less convoluted and used more frequently.
Please note the parentheses:
int result = (my_object.*my_calc_func)(11, 22, 33);
They are almost always needed when using this .* operator, because its precedence is low. Even though my_object .* (my_calc_func(11, 22, 33)) is meaningless, the compiler would try to make sense of it if there were no parentheses.
The ->* operator works in essentially the same way. It would be used if the object on which to apply the method is given by a pointer:
typedef int (*MyClass::CalcResult)(int x, int y, int z);
CalcResult my_calc_func = &MyClass::CalcResult42;
...
MyClass my_object1, my_object2;
MyClass* my_object = flag ? &my_object1 : &my_object2;
int result = (my_object->*my_calc_func)(11, 22, 33);
The .* and ->* operators are called pointer to member access operators and like their name suggests they allow you to access an object's data or function member given an appropriate pointer to that class member.
struct foo
{
int a;
float b;
void bar() { std::cout << "bar\n"; }
};
int main()
{
int foo::* ptra = &foo::a;
float foo::* ptrb = &foo::b;
void (foo::* ptrbar)() = &foo::bar;
foo f;
foo * fptr = &f;
f.*ptra = 5;
f.*ptrb = 10.0f;
(f.*ptrbar)();
fptr->*ptra = 6;
fptr->*ptrb = 11.0f;
(fptr->*ptrbar)();
return 0;
}
I want to perform the following
int p = "xyz"
I should contain 3, i.e, the length of the string on the right side of =.
I tried making a class String with a char * data member but i was having trouble overloading the = operator since we have to pass atleast one object of the class we are overloading the operator for.
please help.
I tried to do the following:
friend void operator=(int, char*)
but it won't work since there is no argument of the class type.
It's impossible to do this, operator= is not overloadable for integer type.
See this answer.
If you use std::string, the solution is simple:
std::string p = "abc";
int l = p.size(); // Better than l = p, because self describing
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
c++ * vs & in function declaration
I know that this probably seems like an incredibly elementary question to many of you, but I have genuinely had an impossible time finding a good, thorough explanation, despite all my best Googling. I'm certain that the answer is out there, and so my search terms must be terrible.
In C++, a variety of symbols and combinations thereof are used to mark parameters (as well as arguments to those parameters). What, exactly, are their meanings?
Ex: What is the difference between void func(int *var) and void func(int **var)? What about int &var?
The same question stands for return types, as well as arguments. What does int& func(int var) mean, as compared to int* func(int var)? And in arguments, how does y = func(*x) differ from y = func(&x)?
I am more than happy to read enormous volumes on the subject if only you could point me in the right direction. Also, I'm extremely familiar with general programming concepts: OO, generics/templates, etc., just not the notation used in C/C++.
EDIT: It seems I may have given the impression that I do not know what pointers are. I wonder how that could be :)
So for clarification: I understand perfectly how pointers work. What I am not grasping, and am weirdly unable to find answers to, is the meaning of, for example 'void func(int &var)'. In the case of an assignment statement, the '&' operator would be on the right hand side, as in 'int* x = &y;', but in the above, the '&' operator is effectively on the left hand side. In other words, it is operating on the l-value, rather than the r-value. This clearly cannot have the same meaning.
I hope that I'm making more sense now?
To understand this you'll first need to understand pointers and references. I'll simply explain the type declaration syntax you're asking about assuming you already know what pointers and references are.
In C, it is said that 'declaration follows use.' That means the syntax for declaring a variable mimics using the variable: generally in a declaration you'll have a base type like int or float followed something that looks like an expression. For example in int *y the base type is int and the expression look-alike is *y. Thereafter that expression evaluates to a value with the given base type.
So int *y means that later an expression *y is an int. That implies that y must be a pointer to an int. The same holds true for function parameters, and in fact for whole function declarations:
int *foo(int **bar);
In the above int **bar says **bar is an int, implying *bar is a pointer to an int, and bar is a pointer to a pointer to an int. It also declares that *foo(arg) will be an int (given arg of the appropriate type), implying that foo(arg) results in a pointer to an int.¹ So the whole function declaration reads "foo is a function taking a pointer to a pointer to an int, and returning a pointer to an int."
C++ adds the concept of references, and messes C style declarations up a little bit in the process. Because taking the address of a variable using the address-of operator & must result in a pointer, C doesn't have any use for & in declarations; int &x would mean &x is an int, implying that x is some type where taking the address of that type results in an int.² So because this syntax is unused, C++ appropriates it for a completely different purpose.
In C++ int &x means that x is a reference to an int. Using the variable does not involve any operator to 'dereference' the reference, so it doesn't matter that the reference declarator symbol clashes with the address-of operator. The same symbol means completely different things in the two contexts, and there is never a need to use one meaning in the context where the other is allowed.
So char &foo(int &a) declares a function taking a reference to an int and returning a reference to a char. func(&x) is an expression taking the address of x and passing it to func.
1. In fact in the original C syntax for declaring functions 'declarations follow use' was even more strictly followed. For example you'd declare a function as int foo(a,b) and the types of parameters were declared elsewhere, so that the declaration would look exactly like a use, without the extra typenames.
2. Of course int *&x; could make sense in that *&x could be an int, but C doesn't actually do that.
What you're asking about are called pointers (*), and reference to (&), which I think is best explained here.
The symbols & and * are used to denote a reference and pointer type, respectively.
int means simply the type 'int',
int* means 'pointer to int',
int& means 'reference to int',
A pointer is a variable which is used to store the address of a variable.
A reference has the syntax of its base type, but the semantics of a pointer to that type. This means you don't need to dereference it in order to change the value.
To take an example, the following code blocks two are semantically equivalent:
int* a = &value;
*a = 0;
And:
int& a = value;
a = 0;
The main reasons to use pointers or references as an argument type is to avoid copying of objects and to be able to change the value of a passed argument. Both of these work because, when you pass by reference, only the address is copied, giving you access to the same memory location as was "passed" to the function.
In contrast, if a reference or pointer type is not used, a full copy of the argument will be made, and it is this copy which is available inside the function.
The symbols * and & have three meanings each in C++:
When applied to an expression, they mean "dereference" and "address-of" respectively, as you know.
When part of a type, they mean "pointer" and "reference", respectively.
Since C++ doesn't care about arbitrary spacing, the declaration int *ptr is exactly the same as the declaration int* ptr, in which you can now more clearly see that this is an object called ptr of type int*.1
When used between two expressions, they mean "multiply" and "bitwise AND", respectively.
1 - though, frustratingly, this isn't actually how the internal grammar reads it, thanks to the nasty legacy of C's type system. So avoid single-line multi-declarations involving pointers unless you want a surprise.
Ex: What is the difference between 'void func(int *var)' and 'void
func(int **var)'? What about 'int &var'?
The same question stands for return types, as well as arguments. What
does 'int& func(int var)' mean, as compared to 'int* func(int var)'?
And in arguments, how does 'y = func(*x)' differ from 'y = func(&x)'?
(1)
<return type> <function name> <parameters>
void func (int *var)
<parameter> here int *var is a pointer to integer, ie it can point to
an array or any buffer that should be handled with integer pointer
arithmetic. In simple terms , var holds the address of the respective
**actual parameter.**
eg: int arr[10];
func(arr);
int a = 33;
func(&a);
Here, &a means we are explicitly passing address of the the variable 'a'.
(2)
int m = 0;
int &var = m;
Here var means reference, ie it another alias name for variable 'm' ,
so any change 'var' makes will change the contents of variable 'm'.
var = 2; /* will change the actual contents of 'm' */
This simple example will not make sense , unless you understand the context.
Reference are usually use to pass parameter to function, so that changes made by
the function to the passed variable is visible at the caller.
int swap(int &m, int &n) {
tmp = m;
m = n;
n = tmp;
}
void main( void ) {
int x = 1, y = 2;
swap(x, y);
/* x = 2, y =1 */
}
(3)
'int& func(int var)' mean, as compared to 'int* func(int var)'?
int& func(int var) means the function returns a reference;
int* func(int var) means the function returns a pointer / address;
Both of the them has its context;
int& setNext() {
return next;
}
setNext() = previous;
where as
int* setNext() {
return &next;
}
int *inptr;
inptr = setNext();
*inptr = previous;
In the previous two lines,
int *inptr <- integer pointer declaration;
*inptr <- means we are accessing contents of the address pointed by inptr;
ie we are actually referring to 'next' variable.
The actual use is context specific. It can't be generalized.
(4)
how does 'y = func(*x)' differ from 'y = func(&x)'?
y = func(&x) is already explained.
y = func(*x) , well i'm not sure if you actually meant *x.
int swap(int *m, int *n) {
tmp = *m;
*m = *n;
*n = tmp;
}
I am trying to understand a program, which includes the following definition for a function f
void f(String S, const String& r)
{
}
Here String in the argument stands for a class. I am confused on the difference between the definitions of these two arguments: "String S" and "const String& r". S should represent an object of class String, then how about r?
In more detail, the f is defined as
void f(String S, const String& r)
{
int c1 = S[1]; // c1=s.operator[](1).operator char( )
s[1] ='c'; // s.operator[](1).operator=('c')
int c2 = r[1]; // c2 = r.operator[](1)
r[1] = 'd'; // error: assignment to char, r.operator[](1) = 'd'
}
This code snippet is to show how the operator overload, but these comments does not help me much. For instance, why r[1]='d' is nor correct? Thanks for helping understanding it.
const String& r is a constant reference to String r. Within the function, you access r just like a String. The difference is that it is actually a reference to the object passed to the function, while S will be a copy of the object passed to the function. You can almost think of it as if you are accessing r through a de-referenced pointer (though there is more to it than that).
Another way to look at it: The caller will see changes to r (if it wasn't const), while he will not see changes to S.
The const simply means the function f cannot modify r.
See also: https://isocpp.org/wiki/faq/references#overview-refs
This seems to be just an example, to show the difference between ways of passing parameters.
One real case where you might pass one parameter by value, is when you need a copy of the value anyway. Perhaps when concatenating the two strings.