I found something interesting. The error message says it all. What is the reason behind not allowing parentheses while taking the address of a non-static member function? I compiled it on gcc 4.3.4.
#include <iostream>
class myfoo{
public:
int foo(int number){
return (number*10);
}
};
int main (int argc, char * const argv[]) {
int (myfoo::*fPtr)(int) = NULL;
fPtr = &(myfoo::foo); // main.cpp:14
return 0;
}
Error: main.cpp:14: error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say '&myfoo::foo'
From the error message, it looks like you're not allowed to take the address of a parenthesized expression. It's suggesting that you rewrite
fPtr = &(myfoo::foo); // main.cpp:14
to
fPtr = &myfoo::foo;
This is due to a portion of the spec (§5.3.1/3) that reads
A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed in parentheses [...]
(my emphasis). I'm not sure why this is a rule (and I didn't actually know this until now), but this seems to be what the compiler is complaining about.
Hope this helps!
Imagine this code:
struct B { int data; };
struct C { int data; };
struct A : B, C {
void f() {
// error: converting "int B::*" to "int*" ?
int *bData = &B::data;
// OK: a normal pointer
int *bData = &(B::data);
}
};
Without the trick with the parentheses, you would not be able to take a pointer directly to B's data member (you would need base-class casts and games with this - not nice).
From the ARM:
Note that the address-of operator must be explicitly used to get a pointer to member; there is no implicit conversion ... Had there been, we would have an ambiguity in the context of a member function ... For example,
void B::f() {
int B::* p = &B::i; // OK
p = B::i; // error: B::i is an int
p = &i; // error: '&i'means '&this->i' which is an 'int*'
int *q = &i; // OK
q = B::i; // error: 'B::i is an int
q = &B::i; // error: '&B::i' is an 'int B::*'
}
The IS just kept this pre-Standard concept and explicitly mentioned that parentheses make it so that you don't get a pointer to member.
Related
From cppreference page on default arguments:
Non-static class members are not allowed in default arguments (even if they are not evaluated), except when used to form a pointer-to-member or in a member access expression:
int b;
class X
{
int a;
int mem1(int i = a); // error: non-static member cannot be used
int mem2(int i = b); // OK: lookup finds X::b, the static member
static int b;
};
I can't understand "except when used to form a pointer-to-member or in a member access expression". And the example does not give the relevant code.
The first part means that you are allowed to form a pointer-to-member to one of the non-static members, e.g.:
class X
{
int a, b;
int mem1(int X::* i = &X::a);
//...
};
A pointer-to-member is a rather obscure part of the language. You have maybe seen member function pointers, but you are also allowed to form such member pointers to data members as above.
The member pointer doesn't refer to the member of the current instance of the class, but needs to be combined with the .* or ->* operators to give the corresponding member of an instance, e.g.:
int X::mem1(int X::* i = &X::a) {
// same as `return a;` if called with default argument
// but if called with `mem1(&X::b)` same as `return b;`
return this->*i;
}
The second part probably just means that it is ok to refer to the member of another instance of the class via the usual member access expressions (using . or ->). The exception doesn't allow referring to the current instance's members since this is also not allowed in the default argument:
class X
{
int a;
static X x;
int mem1(int i = x.a); // ok, `.` is member access
int mem2(int i = this->a); // not ok because of `this`, but `->` is member access
};
Forming a pointer-to-member:
int mem3(int X::*pointer_to_member = &X::a);
Used in a member-access expression:
X global;
int mem4(int i = global.a);
Demo
Functionally and syntactically speaking, is there a difference between a function whose prototype is int foo(void) and int foo(void *)?
I know the difference between, for example, int bar(int) and int bar(int *) - one of them is looking for an int, and the other is looking for an int pointer. Does void behave the same way?
From this answer on Software Engineering, void is treated specially depending on how it's used. In C and C++, void is used to indicate an absence of a data type, whereas void * is used to indicate a pointer which points to some data/space in memory that does not have a type. void * cannot be dereferenced on its own, and must be cast to another type first. This cast need not be explicit in C, but must be explicit in C++. (This is why we don't cast the return value of malloc, which is void *.)
When used with a function as a parameter, void means a total absence of any parameters, and is the only parameter allowed. Attempting to use void like a variable type or include other arguments results in a compiler error:
int foo(void, int); //trying to use "void" as a parameter
int bar(void baz); //trying to use "void" as an argument's type
main.c:1:8: error: 'void' must be the first and only parameter if specified
int foo(void, int);
^
main.c:2:14: error: argument may not have 'void' type
int bar(void baz);
^
It is similarly impossible to declare a variable with type void:
int main(void) {
void qux; //trying to create a variable with type void
}
main.c:5:8: error: variable has incomplete type 'void'
void qux;
void as a return value for a function indicates no data will be returned. Since it is impossible to declare a variable of type void, it is impossible to catch the return value of a void function, even with a void pointer.
void foo(int i) { return; }
int main(void) {
void *j;
j = foo(0);
return 0;
}
main.c:5:5: error: assigning to 'void *' from
incompatible type 'void'
j = foo(0);
^ ~~~~~~
The typeless void * is a different case. A void pointer indicates a pointer to a location in memory, but does not indicate the type of data at that pointer. (This is the used to achieve polymorphism in C, such as with the qsort() function.) These pointers can be tricky to use, however, as it is very easy to accidentally cast them to the wrong type. The code below won't throw any compiler errors in C, but results in undefined behavior:
#include <stdio.h>
int main(void) {
double foo = 47.2; //create a double
void *bar = &foo; //create a void pointer to that double
char *baz = bar; //create a char pointer from the void pointer, which
//is supposed to hold a double
fprintf(stdout, "%s\n", baz);
}
The following code, however, is perfectly legal; casting to and from a void pointer never changes the value it holds.
#include <stdio.h>
int main(void) {
double foo = 47.2;
void *bar = &foo;
double *baz = bar;
fprintf(stdout, "%f\n", *baz);
}
47.200000
As a function parameter, void * indicates that the type of the data at the pointer you are passing in is not known, and it is up to you, the programmer, to properly handle whatever is at that memory location. As a return value, void * indicates that the type of the data being returned is not known or is typeless, and must be handled by the program.
int quux(void *); //a function that receives a pointer to data whose type is not known, and returns an int.
void *quuz(int); //a function that receives an int, and returns a pointer to data whose type is not known.
tl;dr void in a function prototype means "no data" and indicates no return value or no parameters, void * in a function prototype means "the data at the pointer this function is given does not have a known type" and indicates a parameter or return value whose pointer must be cast to a different type before the data at the pointer can be used.
foo(void) - function with no parameters
foo(void *) - function with one void * parameter
What is void *? It is just the pointer to the data with no specified type. It Can be casted to any other pointer type
unsigned add(void *arr)
{
unsigned *uarr = arr;
return uarr[0] + uarr[1];
}
Functionally and syntactically speaking, is there a difference between a function whose prototype is int foo(void) and int foo(void *)?
There is a difference:
int foo(void) declares a function that accepts no arguments.
int foo(void *) declares a function that accepts single argument of type void*.
In C++, int foo(void) is equvalent to int foo().
What is the "operator int" function below? What does it do?
class INT
{
int a;
public:
INT(int ix = 0)
{
a = ix;
}
/* Starting here: */
operator int()
{
return a;
}
/* End */
INT operator ++(int)
{
return a++;
}
};
The bolded code is a conversion operator. (AKA cast operator)
It gives you a way to convert from your custom INT type to another type (in this case, int) without having to call a special conversion function explicitly.
For example, with the convert operator, this code will compile:
INT i(1234);
int i_2 = i; // this will implicitly call INT::operator int()
Without the convert operator, the above code won't compile, and you would have to do something else to go from an INT to an int, such as:
INT i(1234);
int i_2 = i.a; // this wont compile because a is private
operator int() is a conversion operator, which allows this class to be used in place of an int. If an object of this type is used in a place where an int (or other numerical type) is expected, then this code will be used to get a value of the correct type.
For example:
int i(1);
INT I(2); // Initialised with constructor; I.a == 2
i = I; // I is converted to an int using `operator int()`, returning 2.
First things first:
$12.3.1/1 - "A constructor declared
without the function-specifier
explicit specifies a conversion from
the types of its parameters to the
type of its class. Such a constructor
is called a converting constructor."
In your example, INT is a User Defined class that has a converting constructor from 'int'.
Therefore the following code is well-formed:
INT i(1024); // direct initialization syntax
This means that you can get an INT object from an integer. However what does one do, if the INT object has to be converted back to an integer? Transitivity?
One can say that the class INT can provide a member function to return the encapsulated integer member
int x = i.geta();
This however is not very intuitive and is not a standardized approach. Also it is not intuitive when it comes to how built-in types work in such situations.
int z = 0;
int y1 = z; // copy initialization or
int y2(z); // direct initialization
double d = (int )z; // explicit cast
Therefor the Standard allows for such standardization and intuitiveness of converting User Defined Types by saying:
$12.3/2 - "A member function of a
class X having no parameters with a
name of the form [...]
operator conversion-type-id
[...]specifies a conversion from X to the
type specified by the
conversion-type-id. Such functions are
called conversion functions. No return
type can be specified. If a conversion
function is a member function, the
type of the conversion function
(8.3.5) is “function taking no
parameter returning
conversion-type-id”.
This makes all of the following well-formed and retains harmony with the way built-in types work is
int y1 = i; // copy initialization or
int y2(i); // direct initialization
double d = (int )i; // explicit cast
It looks like it make an INT class which behaves a little like the regular int, just that some other operators are not yet defined.
Is this a homework problem?
Seems like it's a question from a classroom, so I'll invite you to check the documentation on how to create a class.
class Foo
{
public
Foo() {} // Constructor
Foo operator++ {} // Operation ++ on foo like:
// Foo foo;
// foo++;
};
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Error with address of parenthesized member function
In this recent question the OP ran into a strange provision of the C++ language that makes it illegal to take the address of a member function if that member function name is parenthesized. For example, this code is illegal:
struct X {
void foo();
};
int main() {
void (X::* ptr)();
ptr = &(X::foo); // Illegal; must be &X::foo
}
I looked this up and found that it's due to §5.3.1/3 of the C++ ISO spec, which reads
A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed in parentheses [...]
Does anyone have any idea why the spec has this rule? It's specific to pointers-to-member, so I would suspect that there is some grammatical ambiguity that this resolves, but I honestly haven't the faintest idea what it might be.
This is just a personal opinion.
If &(qualified-id) is allowed as &(unary-expression),
qualified-id has to be an expression, and an expression is expected to have a type
(even if it is incomplete).
However, C++ didn't have a type which denotes a member, had only
a pointer to member.
For example, the following code cannot be compiled.
struct A { int i; };
template< class T > void f( T* );
int main() {
(void) typeid( A::i );
f( &A::i );
}
In order to make &(qualified-id) be valid, the compiler has to hold
a member type internally.
However, if we abandon &(qualified-id) notation, the compiler doesn't need
to handle member type.
As member type was always handled in the form of a pointer to it,
I guess the standard gave priority to simplify the compiler's type
system a little.
Imagine this code:
struct B { int data; };
struct C { int data; };
struct A : B, C {
void f() {
// error: converting "int B::*" to "int*" ?
int *bData = &B::data;
// OK: a normal pointer
int *bData = &(B::data);
}
};
Without the trick with the parentheses, you would not be able to take a pointer directly to B's data member (you would need base-class casts and games with this - not nice).
From the ARM:
Note that the address-of operator must be explicitly used to get a pointer to member; there is no implicit conversion ... Had there been, we would have an ambiguity in the context of a member function ... For example,
void B::f() {
int B::* p = &B::i; // OK
p = B::i; // error: B::i is an int
p = &i; // error: '&i'means '&this->i' which is an 'int*'
int *q = &i; // OK
q = B::i; // error: 'B::i is an int
q = &B::i; // error: '&B::i' is an 'int B::*'
}
The IS just kept this pre-Standard concept and explicitly mentioned that parentheses make it so that you don't get a pointer to member.
Basically this is a follow up of this question about most vexing parse. I can understand that this is due to the ambiguity between the function declaration and variable definition.
But in Comeau online, I just tired the following.
class T{
public:
T(int i){
}
int fun1(){
return 1;
}
};
int main()
{
T myT(10); // I thought it'd be a function declaration that takes an int and returns a type T
myT.fun1(); // and a compiler error out here.
}
But it compiles fine and there were no errors. I looked into the standard docs but couldn't come to a reasoning.
So, what am I missing here?
Because 10 is not a type. :)
This would be a Most Vexing Parse:
T myT(T());
// T() gets interpreted as function pointer argument to a function returning T();
// This is equivalent to:
T myT(T (*fn)());
Another variety of the Most Vexing Parse is this one:
unsigned char c = 42;
T myT(int(c));
// int(c) gets interpreted as an int argument called c.
// This is equivalent to:
T myT(int c);
The 10 cannot be a parameter type name, so this must be a variable declaration.
The compiler must choose a function declaration when it can do that, but in many cases like this it cannot and there is no ambiguity.
It's not a vexing parse because you used an integer literal rather than, say:
T myT(T());
As in this complete example:
#include <iostream>
struct T { int f() { return 1; } };
int main(int argc, char** argv) {
T t(T());
std::cout << t.f() << '\n';
return 0;
}
Which is ambiguous because it could mean:
myT is a T initialised with a default-constructed T; or
myT is a function returning a T and taking one argument of type T(), which denotes a zero-argument function whose return type is also T.
The latter interpretation is the default one, which is why a compiler error results from attempting to use the newly declared function as though it were the object you expected it to be.
See the Wikipedia article about it.