I have a function Foo and a class CDelegate.
typedef void (*typeFctPtr)(void*);
void Foo(void* dummy)
{
cout << "Foo\n";
}
class CDelegate
{
public:
CDelegate (const typeFctPtr& f_ref_Wrapper, void* f_pvSubscriber)
: m_ref_Wrapper(f_ref_Wrapper), m_pvSubscriber(f_pvSubscriber)
{
}
inline void operator () () const
{
(*m_ref_Wrapper)(0);
}
inline void operator=(const CInterruptDelegate& D)
{
}
private:
void* m_pvSubscriber;
const typeFctPtr& m_ref_Wrapper;
};
A second class has a static member static CDelegate m_Delegate; which I initialize using the constructor like this:
CInterruptDelegate CSpi1::m_Delegate(FreeFunction, 0);
I want to call Foo by calling the ()operator of my static object: CSpi1::m_Delegate();
I get an exception at (*m_ref_Wrapper)(0);
Is there something wrong with the syntax? I am not quite sure if what I try to do is possible at all. I have a working solution where the constructor of CDelegatedoes not take a const reference of a function pointer but the function pointer itself. I can then call the function in the ()operator without problems. I want to use a const reference because the function pointer call cannot be optimized and I hope the call via the const reference can because everything should be known at compile time.
You're holding a reference to a pointer to a function (and the pointer is a temporary which has been destroyed by the time you use it, so things go badly wrong).
Try changing your typedef to be a function type:
typedef void typeFct(void*);
...
const typeFct & m_ref_Wrapper;
Then with your existing code you'll end up with a reference to a function, and you'll be fine. Or you could store a pointer to the function - const typeFct *.
And in either case the call can just be m_ref_Wrapper(0).
In general I prefer to typedef function types rather than pointer-to or reference-to, if only because the syntax is less ugly.
I believe that the problem is the declaration of the member:
const typeFctPtr& m_ref_Wrapper;
Instead, try to drop the &:
const typeFctPtr m_ref_Wrapper;
A reference must always reference another existing object. In this case, it will refer the temporary object created to hold the reference to the pointer at the time the constructor is called.
While we're at it, I would suggest that you should drop the reference from the constructor as well. The reason for this is that there is no gain when you work with scalar:s.
Another thing that would make your code more readable is if you would typedef the type of the function, rather than the pointer to the function. That way, it would be clear that you pass around a pointer.
The following is a cut-down version that summarized the changes I suggest above:
typedef void (typeFct)(void*);
class CDelegate
{
public:
CDelegate (typeFct * f_Wrapper, void* f_pvSubscriber)
: m_ref_Wrapper(f_Wrapper), m_pvSubscriber(f_pvSubscriber)
{
}
inline void operator () () const
{
(*m_ref_Wrapper)(0);
}
private:
void* m_pvSubscriber;
typeFct * m_ref_Wrapper;
};
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.
If we have a function prototype like this :
const CString function(...)
{
CString x;
//do some stuff
return x;
}
does this mean that function returns a const CString ? because const in C++ can be placed in front of a method inside a class to tell the compiler that the attributes will not be modified (or not mutable)
I ask this "dumb" question, because in another case we can have something like this :
static CString function(...)
{ }
And in this case static relates to "function" and not to the variable returned.
In C++ const return_type function_name(params) means you have a function that returns a const return_type. If you have static return_type function_name(params) then this marks the function as static and you no longer need an instance of the class to call this function. If you want to mark a function as const meaning that it will not moodify the class contents then you need to place the const after the function as
return_type function_name(params) const
^^^^^
does this mean that function returns a const CString ?
Yes it does.
because const in C++ can be placed in front of a method inside a class to tell the compiler that the attributes will not be modified (or not mutable)
No it can't, the const has to be placed after the method to achieve that.
class MyClass {
// ...
const CString function();
// ...
}
A function returning const CString.
class MyClass {
// ...
CString const function();
// ...
}
Same thing.
class MyClass {
// ...
CString function() const;
// ...
}
A function that can be called on a constant object, as it "promises" not to change internal state.
As a rule of thumb, const is always after the thing declared constant...
...except for the old C-style const <type>, kept for backward compatibility.
The following two lines are the same thing, a constant pointer to a constant int. Note that to make the pointer constant, the const has to be trailing the *:
const int * const p1; // the exception
int const * const p2;
To return a const value from a function use :
const CString function(...)
{
CString x;
//do some stuff
return x;
}
To tell the compilater that attributes won't change use :
CString myClass::function(...) const
{
CString x;
//do some stuff
return x;
}
const CString function(...) returns a const CString,
but it is deprecated as rarely useful and by the fact that disallows move on the temporary. So, in CString s; s = foo();, a copy is done instead of a move.
The most significant usage was to forbid things like
foo() = CString(..);
C++11 introduces ref qualifier on method and r-value reference which allows to fix that differently:
Obj& operator = (const Obj& rhs) & ; // Note the final &
A function declared as const CString function(...) returns a const CString. This the the same in C++ as it is in C.
If you have a C++ method defined like this:
void MyClass::function(void) cont;
That means that the method function does not modify the object.
const appearing before the method describes the attributes of the return type of the method.
So,
const CString method_name();
means that the method returns a const CString object i.e. an object that cannot be modified by the caller of this method.
const appearing after the method describes the attributes of the method itself. It tells that the method does not "mutate" or "modify" the object it operates on.
So,
const CString method_name() const;
means that the method cannot modify any of the member variables of the object used to invoke the method. It has no relation with the return type of the method.
Let us see this with an example.
class Foo
{
int x;
int GetX() const {return x;}
void SetX(int i_x) {x = i_x;}
};
In the above class definition, GetX() is a const method i.e. it is not expected to modify the object which is used to invoke them. What does this mean? When you declare a class, there is a single version of each of the member functions which gets loaded onto memory. Further, all the non-static member methods need an object to invoke them. How is this achieved? When you declare a non-static member method of the class, the C++ compiler slyly changes the signature of the methods to expect a "this" pointer, that is the pointer to the object used to invoke the method.
For a non-const method, the type of the "this" pointer expected is Class*. So our SetX() method above looks like:
void SetX(Foo* this, int i_x) {this->x = i_x;}
You can use the this pointer to modify the object(x is part of the object right!)
However, for a const method, the type of the "this" pointer passed is
const Class* i.e. you cannot modify the object using the "this" pointer. So GetX becomes
int GetX(const Foo* this) {return this->x; }
Since the type of the this pointer is const Foo*, you cannot change the object the pointer points to i.e. you cannot do someething like:
x = 100;
which would translate to this->x = 100; which the compiler will complain about.
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()
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.
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