In the below given code snippet, when i wrote f = A; then why doesn't A decay to a pointer to a function?
//Func is alias for "pointer to a function that returns an int and does not take any parameter"
typedef int (*Func)();
int A(){
return 1;
}
int main()
{
Func* f = &A;//cannot convert ‘int (*)()’ to ‘int (**)()’ in initialization - I UNDERSTAND THIS ERROR
f = A;//error: cannot convert ‘int()’ to ‘int (**)()’ in assignment - My QUESTION IS THAT IN THIS CASE WHY DOESN'T "A" decay to a pointer to a function and give the same error as the above
}
I know why Func *f = &A; produces error. But i expected f = A; to produce the same error because i thought in this case A will decay to a pointer to a function and hence should produce the same error as Func*f = &A;. To be precise, i thought i would get the error
error: cannot convert ‘int(*)()’ to ‘int (**)()’ in assignment
But to my surprise, there is no decay and i do not get the above error.
Why/How is this so? That is, why is there no decay.
why doesn't A decay to a pointer to a function?
The error message says that a function (int()) cannot be implicitly converted to a pointer to a pointer to a function (int (**)()), because the type of the expression (A) is a function.
The function would decay if there was a valid conversion sequence to the target type through the decayed type. But there isn't such conversion sequence, and so the program is ill-formed.
Related
I created a const pointer which points to an instance of abject allocated dynamically.I could not understand the object itself is const or not.
Firstly I tried to call a non-const member function by using pointer, as expected it caused a compile error because (it is my explanation, don't know if it is true or not) this pointer created by the member function is assigned to that const pointer. It did not yield anything.
Secondly I tried to dereference the pointer and call that non-const member function. I thought that the this pointer created by member function now will not be a const pointer because compile can not know the object returned by p (namely *p) is returned by a const pointer or not. It turns out that I was mistaken.
How does member-function understand that ?
#include<iostream>
class A
{
int a=4;
public:
A()
{}
void print()
{
std::cout<<a<<std::endl;
}
};
int main()
{
const A* p = new A();
p->print(); //1 causes compile error
(*p).print(); //2 causes compile error
return 0;
}
I thought the line labelled as 2 will not create a compile error.
It causes a compile error.The error message is:
"a.cpp: In function ‘int main()’:
a.cpp:21:13: error: passing ‘const A’ as ‘this’ argument discards qualifiers [-fpermissive]
p->print(); //1 causes compile error
^
a.cpp:10:9: note: in call to ‘void A::print()’
void print()
^~~~~
a.cpp:22:15: error: passing ‘const A’ as ‘this’ argument discards qualifiers [-fpermissive]
(*p).print(); //2 causes compile error
^
a.cpp:10:9: note: in call to ‘void A::print()’
void print()
^~~~~
Variables have types and can therefore be const or non-const, but expressions have types too. The type of (*p) is const A, and you can't call a non-const method of a const type.
There is no difference between (1) and (2). (1) is syntax sugar for (2).
You should define the print method as const in order to call it for const object.
void print() const { ... }
As it has already been noted, expressions have types and the type of (*p) is const A. You cannot call a non-const function on an object of a const type but you can call const member function. Member functions can have a const qualifier which will mark them to be able to be invoked on const objects or pointers to const objects.
void print() const
{
std::cout<<a<<std::endl;
}
This will make your code compile. and it looks like this is what you intended to do anyway.
GCC and Clang both reject the C-style cast in the following code.
http://coliru.stacked-crooked.com/a/c6fb8797d9d96a27
struct S {
typedef const int* P;
operator P() { return nullptr; }
};
int main() {
int* p1 = const_cast<int*>(static_cast<const int*>(S{}));
int* p2 = (int*)(S{});
}
main.cpp: In function 'int main()':
main.cpp:7:25: error: invalid cast from type 'S' to type 'int*'
int* p2 = (int*)(S{});
main.cpp:7:15: error: cannot cast from type 'S' to pointer type 'int *'
int* p2 = (int*)(S{});
^~~~~~~~~~~
However, according to the standard, a C-style cast can perform the conversions performed by a static_cast followed by a const_cast. Is this code well-formed? If not, why not?
This is core issue 909:
According to 5.4 [expr.cast] paragraph 4, one possible interpretation
of an old-style cast is as a static_cast followed by a const_cast. One
would therefore expect that the expressions marked #1 and #2 in the
following example would have the same validity and meaning:
struct S {
operator const int* ();
};
void f(S& s) {
const_cast<int*>(static_cast<const int*>(s)); // #1
(int*) s; // #2
}
However, a number of implementations issue an error on #2.
Is the intent that (T*)x should be interpreted as something like
const_cast<T*>(static_cast<const volatile T*>(x))
Rationale (July, 2009):
According to the straightforward interpretation of the wording, the example should work. This appears to be just a compiler bug.
This was apparently never resolved by neither Clang nor GCC. Time to open tickets.
I was amazed to find out that GCC allows functions to return arrays when trailing return type is used instead of normal one. As you probably knows arrays can't be copied so this is quite limited but let me show you some cool example.
#include <iostream>
#include <typeinfo>
using namespace std;
auto func() -> int [5]
{
return {4, 56, 78, 4, 0};
}
int main()
{
cout << func()[2] << endl;
cout << typeid(func).name() << endl;
}
Is this a compiler bug or some new feature?
Interestingly 'typeid' returns 'FA5_ivE' which is demangled as 'int (()) [5]' and this means exactly what you think an function returning array of 5 int's.
EDIT: I tried bounding the returned array into rvalue reference but without any success (used most of the possible forms):
auto &&refArrayTemp{ func() };
Seems that this extensions is rather useless.
This was a bug in gcc (fixed as of 2017-07-03), caused by inconsistent treatment of trailing-return-types.
First note the difference in error message between two attempts to declare a function returning a function:
using Fv = void();
Fv f1(); // error: 'f1' declared as function returning a function
auto f2() -> Fv; // error: function return type cannot be function
The first error comes from decl.c, handling declarators, while the second is a lot deeper into the internals, from tree.c, attempting to build the function type preparatory to generating code.
Trailing-return-types are handled in decl.c 30 lines below the above error - too late to catch it with the above error code, and it is not handled separately.
With arrays, similarly using a trailing-return-type allows us to skip the checks in decl.c, the difference being that function-returning-array is actually valid in terms of gcc's internal representation.
Note that you can't do much with it; gcc doesn't allow you to assign, reference-bind, decay or pass the result of func() to another function:
auto a1 = func();
// error: invalid use of non-lvalue array
auto& a2 = func();
// error: invalid initialization of non-const reference of type 'int (&)[5]' from an rvalue of type 'int [5]'
auto&& a3 = func();
// error: lvalue required as unary '&' operand
Indeed, even your code is rejected at -Wpedantic:
warning: ISO C++ forbids subscripting non-lvalue array
Finally, by exploiting a similar bug (qualifiers are stripped from scalars before handling of trailing-return-types) we can create a function with type int const volatile():
int const volatile g1(); // warning: type qualifiers ignored on function return type
auto g2() -> int const volatile; // OK!!
Latest draft, [dcl.array]/p10:
Functions shall not have a return type of type array or function, although they may have a return type of
type pointer or reference to such things. There shall be no arrays of functions, although there can be arrays
of pointers to functions.
This could be a non-standard GCC extension. It doesn't compile in the trunk version of clang. However, this may also be a bug since it has inconsistent behavior with a non-trailing return type.
I've tried this declaration:
using fp_type = void (*)(fp_type);
Unsurprisingly, it does not work.
a.cpp: In function 'int main()':
a.cpp:13:26: error: expected ';' before '(' token
using fp_type = void(*)(fp_type);
^
a.cpp:13:34: error: expected primary-expression before ')' token
using fp_type = void(*)(fp_type);
Is there a workaround? I was thinking about a reinterpret_cast from a dummy function pointer type, but I am not sure how standard-compliant that is. I am looking into this because I don't want to capture a lambda in a ::std::function, and then use it recursively. I'd like to pass it a function pointer to itself.
5.2.10/6 guarantees you can reinterpret_cast a function pointer to a function pointer of different type, and when you cast it back to the original type, you get back the original pointer value.
I would prefer this:
void foo (struct foo_wrapper&);
struct foo_wrapper {
void (*pf) (struct foo_wrapper&);
// add constructor and accessor for convenience
};
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.