Is casting the constness of member function pointers defined in C++? Is the following valid code?
struct T {
void foo(int i) const { std::cout << i << std::endl;};
};
void (T::*f1)(int) const = &T::foo;
void (T::*f2)(int) = reinterpret_cast<void (T::*)(int)>(f1);
T t;
(t.*f2)(1);
Update:
The reason why I need this is that I'm writing a function that accepts both an object and a member function pointer to that object. I need a version for const objects (accepting only const functions) and a normal one. Since I don't want duplicate code, my idea was to put the actual code in the non-const version and call it from the const one, casting away any consts.
Compiler eats it.
But the backward cast is more useful.
And again but - it is better to don't use it, const_cast is usually just a quick and dirty solution, which you apply only when there are not any other solution.
Answer to update
If I understand you correctly you are going to use one object and two function. First function accepts const object and const member-function, second - non-const object and non-const member-function.
According to given information you can change second function to accept non-const object and const member-function. And give them one non-const object and its const member-function.
Yes, it is defined, but you maybe don't want it if the function is really const, because some compiler optimizations (namely return value caching) depend on the function being const.
You can do it, but it has no meaning, wherever you can call f2, you can also call f1 too. You should cast in the other way. But if something, you should cast the object, not the function.
void (T::*f1)(int) const = &T::foo;
void (T::*f2)(int) = reinterpret_cast<void (T::*)(int)>(f1);
T t;
(t.*f2)(1); // compiles
(t.*f1)(1); // this compiles too!!
but if you have
const T t;
(t.*f2)(1); // error t is const
(t.*f1)(1); // still compiles
The only was to resolve the ambiguity is to perform a static_cast, this is basically a language feature
#include <boost/typeof/typeof.hpp>
struct Test
{
const int& foo();
const int& foo() const;
};
int main()
{
typedef const int&(Test::*non_const_ptr)();
typedef const int&(Test::*const_ptr)()const;
BOOST_TYPEOF(static_cast<non_const_ptr>(&Test::foo)) ss;
}
I don't see a reason for doing this: even if you could, you'd make it more restrictive.
Let's say you have a class Foo:
class Foo {
void f() const;
void g();
}
And some snippet of code:
Foo a;
const Foo b;
Then you can call both a.f() and a.g(), but not b.g() because b is const. As you can see, placing const after a member function makes it less restrictive, not more.
And, by reinterpret_casting this pointer, you'll get the pointer with exact same value(due to the nature of reinterpret_cast), and if you try to call it, you'll get into the same T::foo()
Related
A co-worker asked about some code like this that originally had templates in it.
I have removed the templates, but the core question remains: why does this compile OK?
#include <iostream>
class X
{
public:
void foo() { std::cout << "Here\n"; }
};
typedef void (X::*XFUNC)() ;
class CX
{
public:
explicit CX(X& t, XFUNC xF) : object(t), F(xF) {}
void execute() const { (object.*F)(); }
private:
X& object;
XFUNC F;
};
int main(int argc, char* argv[])
{
X x;
const CX cx(x,&X::foo);
cx.execute();
return 0;
}
Given that CX is a const object, and its member function execute is const, therefore inside CX::execute the this pointer is const.
But I am able to call a non-const member function through a member function pointer.
Are member function pointers a documented hole in the const-ness of the world?
What (presumably obvious to others) issue have we missed?
The constness of execute() only affects the this pointer of the class. It makes the type of this a const T* instead of just T*. This is not a 'deep' const though - it only means the members themselves cannot be changed, but anything they point to or reference still can. Your object member already cannot be changed, because references cannot be re-seated to point to anything else. Similarly, you're not changing the F member, just dereferencing it as a member function pointer. So this is all allowed, and OK.
The fact that you make your instance of CX const doesn't change anything: again, that refers to the immediate members not being allowed to be modified, but again anything they point to still can. You can still call const member functions on const objects so no change there.
To illustrate:
class MyClass
{
public:
/* ... */
int* p;
void f() const
{
// member p becomes: int* const p
*p = 5; // not changing p itself, only the thing it points to - allowed
p = NULL; // changing content of p in const function - not allowed
}
};
In this context object is a reference to a X, not a reference to a const X. The const qualifier would be applied to the member (i.e. the reference, but references can't be const), not to the referenced object.
If you change your class definition to not using a reference:
// ...
private:
X object;
// ...
you get the error you are expecting.
The instance object of class X is not const. It is merely referenced by an object which is const. Const-ness recursively applies to subobjects, not to referenced objects.
By the alternative logic, a const method wouldn't be able to modify anything. That is called a "pure function," a concept which doesn't exist in current standard C++.
You are calling foo on object, not on this.
Since object is declared as an X&, in a constant CX, it is actually an X& const (which is not the same as const X&) allowing you to call non const methods on it.
One helpful way of thinking about it might be that your X object is not a member of CX at all.
I have the following code:
class MyClass;
typedef void(MyClass::*func_ptr)();
class MyClass
{
public:
MyClass()
{
f = &MyFunc1;
}
void MyFunc1()
{
// ...
}
void MyFunc2() const
{
(this->*f)();
}
func_ptr f;
};
If I try to compile, it fails because of MyFunc2() which is a const method trying to call the function pointer of type func_ptr which is non-const.
I'm trying to figure out the best way to cast this. I can use a standard C style cast:
typedef void(MyClass::*func_ptr2)() const;
func_ptr2 f2 = (func_ptr2)f;
(this->*f2)();
But I'd prefer to use a C++ cast (i.e. static_cast, reinterpret_cast, or const_cast). I got this to compile with reinterpret_cast but I can't get it working with const_cast. I thought const_cast was mean't to be used for this case? Also, is there a cleaner way to do this without having to create another typedef?
The typical solution would be (const_cast<MyClass*>(this)->*f)();.
This is legal as long as the MyClass instance has been created non-const.
Else, this would invoke undefined behavior.
There are a couple of issues in this code.
f = &MyFunc1;
Is not well-formed C++ because taking an address of a non-static member function requires a fully qualified name:
f = &MyClass::MyFunc1;
this is MyClass const* in a const member function. You may need to cast away that const:
(const_cast<MyClass*>(this)->*f)();
A better solution may be to rethink the design to avoid fighting the type system with const_cast.
The following seems to compile:
MyClass()
{
f = &MyClass::MyFunc1;
}
void MyFunc1()
{
// ...
}
void MyFunc2() const
{
MyClass* mc = const_cast<MyClass*>(this);
(mc->*f)();
}
is it ok to use const_cast in that case or are there any caveats:
class A{
public:
A() : m_someData(5)
{}
int& get() { return m_someData;};
const int& get() const { const_cast<A*>(this)->get(); };
private:
int m_someData;
};
the intention is that the get routine may be much more complicated and code duplication should be avoided.
No. I wouldn't suggest that. I would suggest you to use const_cast in reverse direction:
int& get() { return const_cast<int&>(const_cast<A const &>(*this).get()); };
const int& get() const { return m_someData; };
That is, you should call the const member function from non-const overload, not the other way round. That way, you ensure that even the non-const version doesn't change the state of the object and the code in both functions are indeed same (because you call the const version eventually) — and there would be certainly code duplication which you want to avoid.
If you do this the other way round, the compiler will not tell you if you modify the object in non-const version of the function and it would be incorrect to call such function from const function.
If I do this:
// In header
class Foo {
void foo(bar*);
};
// In cpp
void Foo::foo(bar* const pBar) {
//Stuff
}
The compiler does not complain that the signatures for Foo::foo do not match. However if I had:
void foo(const bar*); //In header
void Foo::foo(bar*) {} //In cpp
The code will fail to compile.
What is going on?
I'm using gcc 4.1.x
In the first, you've promised the compiler, but not other users of the class that you will not edit the variable.
In your second example, you've promised other users of the class that you will not edit their variable, but failed to uphold that promise.
I should also note that there is a distinct difference between
bar* const variable
and
const bar* variable
and
const bar* const variable
In the first form, the pointer will never change, but you can edit the object that is pointed to. In the second form, you can edit the pointer(point it to another object), but never the variable that it points to. In the final form, you will neither edit the pointer, nor the object it points to. Reference
To add a bit more of a clarification to the question stated, you can always promise MORE const than less. Given a class:
class Foo {
void func1 (int x);
void func2 (int *x);
}
You can compile the following implementation:
Foo::func1(const int x) {}
Foo::func2(const int *x) {}
or:
Foo::func1(const int x) {}
Foo::func2(const int* const x) {}
without any problems. You've told your users that you may possibly edit their variables. In your implementation, you've told the compiler that this particular implementation will not edit those variables, even though the told the users you might. You haven't broken a promise to the user, and so the code compiles.
See this question, this question, and this question.
Basically, the const only means that the function will not modify the pointer's value. The pointers contents are not const, the same as the header's signature.
The const keyword in the first example is meaningless. You are saying that you don't plan on changing the pointer. However, the pointer was passed by value and so it dos not matter if you change it or not; it will not effect the caller. Similarly, you could also do this:
// In header
class Foo {
void foo( int b );
};
// In cpp
void Foo::foo( const int b ) {
//Stuff
}
You can even do this:
// In header
class Foo {
void foo( const int b );
};
// In cpp
void Foo::foo( int b ) {
//Stuff
}
Since the int is passed by value, the constness does not matter.
In the second example you are saying that your function takes a pointer to one type, but then implement it as taking a pointer to another type, therefore it fails.
So the second const in:
void Foo::foo(const bar* const);
Is not part of the method signature?
This is simpler to understand with a variable type other than a pointer. For example, you can have the following function declaration:
void foo( int i );
The definition can look like this:
void foo( const int i ) { ... }
Whether the variable 'i' is const or not on the definition side is an implementation detail. It has no impact for the clients of that function.
It probably doesn't care much about void Foo::foo(bar* const pBar) because how you treat the pointer itself (const or not) doesn't matter one bit outside of the routine. The C rules say that no change to pBar will travel outside of foo either way.
However, if it is (const bar* pBar), that makes a difference, because it means the compiler is not to allow callers to pass in pointers to non-const objects.
In the former, the const doesn't affect the interface, only the implementation. You are saying to the compiler, "I am not going to change the value of the bar* within this function". You can still change what is pointed to by the pointer. In the latter, you are telling the compiler (and all callers) that you will not change the bar structure that the bar* points to.
Here is an example of what I want to accomplish and how:
class MyClass
{
public:
void Dummy() const{}
};
typedef void (MyClass::*MemFunc)();
void (const MyClass * instance)
{
MemFunc func=&MyClass::Dummy;
// (instance->*func)(); //gives an error
(const_cast<MyClass *>instance->*func)(); // works
}
Why do compilers (gcc 3 & 4) insist that instance should be non-const? Would that const_cast cause issues?
FYI: instance` is not necessarily const, I just don't want a callee to mess with it.
What is happening here?
The error is in the line before. Change the typedef to
typedef void (MyClass::*MemFunc)() const;
To make it a pointer to a const member function type.
The difference might be more clear when considering this code and how it works:
typedef void FunctionType() const;
typedef FunctionType MyClass::*MemFunc;
A member-function pointer in particular is actually just a special case of a member-pointer in general. For a const member function, the function type of the member function is different than for a non-const member function. That is why the types have to match.
typedef void (MyClass::*MemFunc)();
Here you are defining a pointer to a function which might modify its object.
MemFunc func=&MyClass::Dummy;
Here you are assigning a function which won't change it's object to such a pointer. This is legal, since not changing is a subset of might change.
(instance->*func)();
Here you are trying to call a function which might change its object, using an object which cannot be changed.
You will need to change the definition of MemFunc