struct test
{
void f() {};
};
test t1;
using memfun_t = void (test::*)();
memfun_t mf = &test::f;
auto a1 = &test::f; // OK
auto a2 = t1.*mf; // error
auto a3 = &(t1.*mf); // still no luck
Any ideas why this can't be deduced? I would appreciate answers referencing the Standard.
Edit :
I have found a RAD Studio language extension called __closure that appears to be addressing this issue.1 Here is the code :
class base {
public:
void func(int x) {
};
};
typedef void(base::*pBaseMember)(int);
class derived : public base {
public:
void new_func(int i) {
};
};
int main(int argc, char * argv[]) {
derived derivedObject;
void(__closure * derivedClosure)(int);
// Get a pointer to the ‘new_func’ member.
// Note the closure is associated with the
// particular object, ‘derivedObject’.
derivedClosure = derivedObject.new_func;
derivedClosure(3); // Call ‘new_func’ through the closure.
return 0;
}
http://docwiki.embarcadero.com/RADStudio/Seattle/en/Closure
You can't use
auto a2 = t1.*mf; // error
just like you can't use:
auto a2 = t1.f;
t1.f is not a valid expression. A pointer to a member function cannot be obtained through an instance of the class. Unlike non-member functions, which decay to a function pointer when used like that, member functions don't decay to a member function pointer.
Relevant text from the C++11 Standard:
Unary Operators
...
4 A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed in parentheses. [ Note: that is, the expression &(qualified-id), where the qualified-id is enclosed in parentheses, does not form an expression of type “pointer to member.” Neither does qualified-id, because there is no implicit conversion from a qualified-id for a non-static member function to the type “pointer to member function” as there is from an lvalue of function type to the type “pointer to function” (4.3). Nor is
&unqualified-id a pointer to member, even within the scope of the unqualified-id’s class. —end note ]
Related
I have some code which requires me to use *this, but I want it to be noexcept friendly:
struct foo;
// Would actually be something with conditional noexcept
void do_something(foo&);
struct foo {
void fn()
noexcept(noexcept(::do_something(*this)))
{
::do_something(*this);
}
};
However, gcc rejects this:
<source>:7:43: error: invalid use of 'this' at top level
noexcept(noexcept(::do_something(*this)))
If I just access a member, gcc is fine:
void do_something(int);
struct bar {
int x;
void fn()
noexcept(noexcept(::do_something(x)))
{
::do_something(x);
}
};
However, if I access the member through the this pointer, gcc complains again:
struct baz {
int x;
void fn()
noexcept(noexcept(::do_something(this->x)))
{
::do_something(this->x);
}
};
Diagnostic:
<source>:7:42: error: invalid use of 'this' at top level
noexcept(noexcept(::do_something(this->x)))
Every other compiler I tried accepts using this inside the noexcept specification, but I don't actually know if it's gcc that has the bug or all the other compilers.
Can the keyword this be used inside a noexcept specification?
Yes, it is allowed. [expr.prim.this]p2 says:
If a declaration declares a member function or member function template of a class X, the expression this is a prvalue of type “pointer to cv-qualifier-seq X” between the optional cv-qualifier-seq and the end of the function-definition, [...].
The cv-qualifier-seq refers to the cv qualifiers of the member function, which appear before the noexcept specifier:
parameters-and-qualifiers:
( parameter-declaration-clause ) cv-qualifier-seq[opt] ref-qualifier[opt]
noexcept-specifier[opt] attribute-specifier-seq[opt]
So, this is a valid expression to use in the noexcept-specifier. This was a DR (cwg1207), which gcc doesn't implement. The bug report.
struct A
{
void f() {}
};
void f() {}
int main()
{
auto p1 = &f; // ok
auto p2 = f; // ok
auto p3 = &A::f; // ok
//
// error : call to non-static member function
// without an object argument
//
auto p4 = A::f; // Why not ok?
}
Why must I use address-of operator to get a pointer to a member function?
auto p1 = &f; // ok
auto p2 = f; // ok
The first is more or less the right thing. But because non-member functions have implicit conversions to pointers, the & isn't necessary. C++ makes that conversion, same applies to static member functions.
To quote from cppreference:
An lvalue of function type T can be implicitly converted to a prvalue
pointer to that function. This does not apply to non-static member
functions because lvalues that refer to non-static member functions do
not exist.
struct X {
int f(int);
static int f(long);
};
int (X::*p1)(int) = &X::f; // OK
int (*p2)(int) = &X::f; // error: mismatch
int (*p3)(long) = &X::f; // OK
int (X::*p4)(long) = &X::f; // error: mismatch
int (X::*p5)(int) = &(X::f); // error: wrong syntax for pointer to member
int (*p6)(long) = &(X::f); // OK
I think that p1 and p5 is the same case. Why is p5 wrong?
Because the standard says so. From the N3936:
5.3.1 Unary operators
A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed in parentheses. [ Note:
that is, the expression &(qualified-id), where the qualified-id is
enclosed in parentheses, does not form an expression of type “pointer
to member.” Neither does qualified-id, because there is no implicit
conversion from a qualified-id for a non-static member function to the
type “pointer to member function” as there is from an lvalue of
function type to the type “pointer to function” (4.3). Nor is
&unqualified-id a pointer to member, even within the scope of the
unqualified-id’s class. — end note ]
The C++ Standard's definition of the built-in operator & states that only when the parameter to & is a qualified-id, meaning something like Class::Member, does & result in a pointer-to-member. The parentheses make it no longer a qualified-id, so it attempts to parse X::f directly, which is illegal in this context: you're assigning an int (*)(long) to an int (X::*)(int).
The distinction between the two cases resolves an ambiguity. Let's say that you have:
struct X {
int m;
};
struct Y {
int m;
};
struct Z : X, Y {
void F();
};
void Z::F() {
int X::*p1 = &X::m;
int *p2 = &(X::m);
}
Here, &X::m is a pointer-to-member, whereas &(X::m) is an ordinary pointer to int, using the X:: qualification to resolve the ambiguity between X's m and Y's m.
clang doesn't compile the third call to typeid below (see live example). But I can't see anything in §5.2.8 that disallows this, specially when we consider that the expression B::f is not a glvalue of polymorphic class type (see paragraph 3). Also, according to this paragraph the expression B::f is an unevaluated operand, and as such, the call typeid(B::f) should compile. Note that GCC doesn't compile any of the calls to typeid below:
#include <iostream>
#include <typeinfo>
struct A{ int i; };
struct B{ int i; void f(); };
int main()
{
std::cout << typeid(A::i).name() << '\n';
std::cout << typeid(B::i).name() << '\n';
std::cout << typeid(B::f).name() << '\n';
}
As far as I can tell clang is correct, using a non static member is only valid in an unevaluated context if it is a data member. So it looks like gcc is incorrect for the first two cases, but gcc works correctly in the case of sizeof and decltype which also have unevaluated operands.
From the draft C++11 standard section 5.1.1 [expr.prim.general]:
An id-expression that denotes a non-static data member or non-static
member function of a class can only be used:
and includes the following bullet:
if that id-expression denotes a non-static data member and it appears
in an unevaluated operand. [ Example:
struct S {
int m;
};
int i = sizeof(S::m); // OK
int j = sizeof(S::m + 42); // OK
—end example ]
The rest of the bullets do not apply, they are as follows:
as part of a class member access (5.2.5) in which the object expression refers to the member’s class61 or a class derived from that
class, or
to form a pointer to member (5.3.1), or
in a mem-initializer for a constructor for that class or for a class derived from that class (12.6.2), or
in a brace-or-equal-initializer for a non-static data member of that class or of a class derived from that class (12.6.2), or
We know that operand is unevaluated from section 5.2.8 which says:
When typeid is applied to an expression other than a glvalue of a
polymorphic class type, [...] The expression is an unevaluated operand
(Clause 5).
We can see from the grammar that an id-expression is either an unqualified-id or a qualified-id:
id-expression:
unqualified-id
qualified-id
Update
Filed a gcc bug report: typeid does not allow an id-expression that denotes a non-static data member.
typeid(A::i).name() doesn't quite do what I thought it would do. I expected it to be a pointer-to-member, but it's actually just an int.
To see this, run this code:
#include <iostream>
struct A{ int i; };
struct B{ int i; void f(void); };
template<typename T>
void what_is_my_type() {
std:: cout << __PRETTY_FUNCTION__ << std:: endl;
}
int main()
{
what_is_my_type<decltype(&A::i)>(); // "void what_is_my_type() [T = int A::*]"
what_is_my_type<decltype(&B::i)>(); // "void what_is_my_type() [T = int B::*]"
what_is_my_type<decltype(&B::f)>(); // "void what_is_my_type() [T = void (B::*)()]"
what_is_my_type<decltype(A::i)>(); // "void what_is_my_type() [T = int]"
what_is_my_type<decltype(B::i)>(); // "void what_is_my_type() [T = int]"
// what_is_my_type<decltype(B::f)>(); // doesn't compile
}
I've put the output in a comment after each call.
The first three calls work as expected - all three work and the type information includes the type of the struct (A or B) as well as the type of member.
The last three are different though. The final one doesn't even compile, and the first two simply print int. I think this is a clue as to what is wrong. It is possible, given a particular A or B, to take the address of that particular member:
A a;
int * x = &(a.i);
*x = 32;
but it is not possible (or even meaningful?) to do this:
B b;
??? y = &(a.f); // what does this even mean?
Finally, to emphasize that this is not about pointers, consider this:
A a;
B b;
int x = a.i;
int y = b.i;
??? z = b.f; // what would this mean? What's its type?
struct B
{
};
struct A
{
operator A&() const;
operator B&() const;
};
int main()
{
const A a;
B& br = a;
A& ar = a;
}
Why can I create cast operator to B&, but not to A&.
May be it does not have much sense (one can use it to erase const modifier, as in example), but it at least inconsistent!
You can't do this because it's explicitly forbidden. N3290 § 12.3.2 states:
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”. A
conversion function is never used to convert a (possibly cv-qualified) object to the (possibly cv-qualified)
same object type (or a reference to it), to a (possibly cv-qualified) base class of that type (or a reference to
it), or to (possibly cv-qualified) void.
(Emphasis mine)
This is discussed further in a note:
These conversions are considered as standard conversions for the purposes of overload resolution (13.3.3.1, 13.3.3.1.4) and
therefore initialization (8.5) and explicit casts (5.2.9).
Which explains this decision - it would interfere with the built-in mechanics too much. (For little gain).
If you really want something non-const from a const object the only smart way to do this is constructing a new instance using the copy constructor.
As a work around you could introduce a lightweight intermediary (like a smart pointer):
struct B {};
struct A {};
namespace {
B b_inst;
A a_inst;
}
struct A_wrapper {
A& inst;
// This is perfectly fine: const alters the reference, not what it refers to
operator A&() const { return inst; }
operator B&() const { return b_inst; }
A_wrapper() : inst(a_inst) {}
};
int main() {
const A_wrapper a;
B& br = a;
A& ar = a;
}
But really, wanting to do this in the first place looks like a code smell.
The proper way to do this would be to use const_cast.
For example,
#include <iostream>
using namespace std;
void f(int* p) {
cout << *p << endl;
}
int main(void) {
const int a = 10;
const int* b = &a;
// Function f() expects int*, not const int*
// f(b);
int* c = const_cast<int*>(b);
f(c);
// Lvalue is const
// *b = 20;
// Undefined behavior
// *c = 30;
int a1 = 40;
const int* b1 = &a1;
int* c1 = const_cast<int*>(b1);
// Integer a1, the object referred to by c1, has
// not been declared const
*c1 = 50;
return 0;
}
Declaring a conversion to a reference to self is not ill-formed. Your problem comes at the time where your reference is initialized. As the type of the reference and the type of the initialization expression are the same, the reference is bound directly and your user defined conversion operator is never considered. Thus normal conversion rules apply and const conversion makes the code ill-formed.
Anyway, what your are doing is basically asking yourself to get shot in the foot. If you don't like constness, don't use it. If you do it consistently, it will never bother you, but it is not going to make you new friends.