I have some overloaed methods which take some different pointer types.
Now I want to call one specific method with nullptr as a parameter.
I know that I could cast the nullptr to the specific type of pointer, the method I want it to call takes.
But I don't want to/can't cast the nullptr.
This example shoud explain what I am trying to do:
class Foo {
//some attributes
};
class Bar {
//some attributes
};
void myMethod (Foo*) {
//I want this method to be called
}
void myMethod (Bar*) {
//Not this one
}
int main () {
myMethod(nullptr); //Something like this
// myMethod(static_cast<nullptr>); //I don't want to write this.
return 0;
}
If I just call it with the nullptr I get
error: call of overloaded 'myMethod(std::nullptr_t)' is ambiguous
because the compiler doesn't know which of the methods it should call.
Is there a way to do what I want?
Like something similar to the template specialization?
You can create an overload which take std::nullptr_t as argument, and then in it call the exact function wanted (through casting):
void myMethod(std::nullptr_t)
{
myMethod(static_cast<Foo*>(nullptr));
}
You can create pointer of Foo and Bar and let both point to nullptr. Now you can call a overloaded function by passing pointer variable as argument.
class Foo {
//some attributes
};
class Bar {
//some attributes
};
void myMethod (Foo*) {
//I want this method to be called
}
void myMethod (Bar*) {
//Not this one
}
int main () {
Foo* foo=nullptr;
Bar* bar=nullptr;
myMethod(foo); //This will call myMethod(Foo*)
return 0;
}
Some programmer dude has a good suggestion, but you could also add a default parameter to one of your methods if you were happy to call it without passing nullptr, like so:
void myMethod (Foo* = nullptr) {}
void myMethod (Bar*) {}
int main () {
myMethod();
}
Like something similar to the template specialization?
If that means that you wish to specify the target class on a case by case basis, you can turn the overload in #Some programmer dude's answer into a template.
template<class C>
void myMethod(std::nullptr_t) {
myMethod(static_cast<C*>(nullptr));
}
Now you can use a simple template name to call the overload you want
myMethod<Foo>(nullptr); // What you want now.
myMethod<Bar>(nullptr); // What you may want at another point.
myMethod<Baz>(nullptr); // What you may want sometime in the future,
// after adding another overload.
Related
I've read several topics about that kind of problem - but can't find a simple and good solution. Here is the code:
void SomeFunction() { }
class A {
public:
typedef std::function<void(void)> AFunction;
static void AMethod(AFunction f) { f(); }
};
class B {
public:
void B1Method() { }
void BCorrectCall() { A::AMethod(SomeFunction); }
void BIncorrectCall() { A::AMethod(B1Method); }
};
Problem is here void BIncorrectCall() { A::AMethod(B1Method); }, where I receive error about invalid casting. What is the simplest way to achieve that kind of behaviour? Thanks a lot for any advice!
Use a lambda:
A::AMethod([this]{B1Method();});
It doesn't matter in this case, but if you wanted to store AFunction f and use it after the call to AMethod, you'd have to ensure that the B instance (the address of which is saved in the lambda) says alive as long as you use the function.
C++17 allows you to capture *this instead, which will copy the entire B instance into lambda, but normally it's not what you want.
You could do something similar with std::bind (see the other answer), but lambdas are more flexible.
B1Method is not void(*)(void), it's void(B1::*)(void).
You may do
void BIncorrectCall() { A::AMethod(std::bind(&B1::B1Method, this)); }
};
The issue is that B::B1Method() is a non-static member function in B and, therefore, it needs to be called on an instance of B.
If the implementation of B1Method() doesn't use any non-static data member of B and it doesn't call any other non-static member function of B, then simply declaring it as static will work with your current implementation of BIncorrectCall() as you will no longer need to call B1Method() on an instance of B:
class B {
public:
static void B1Method() { } // static now
void BCorrectCall() { A::AMethod(SomeFunction); }
void BIncorrectCall() { A::AMethod(B1Method); } // no change
};
Otherwise, you have to keep an object of type B whenever you want to call B1::B1Method().
The easiest way is to make it static and so there is no this object, but if you need it (the this object), you can use lambdas:
class B {
public:
void B1Method() { }
void BCorrectCall() { A::AMethod(SomeFunction); }
void BIncorrectCall() {
std::function<void(void)> el = [&](){this->B1Method();};
A::AMethod(el);
}
};
The problem is that 'B1Method' is not a simple function - it's a class method. That means that when you call myB.B1Method(), you're actually calling 'B1Method(&myB)', effectively passing the this pointer as a hidden argument - so you can't convert M1Method to a std::function without specifying which object it should act on.
One approach that should work is using std::bind to construct a callable object from a combination of an object (class instance) and the method. Something like:
void BNowCorrectCall() { A::AMethod(std::bind(&B::B1Method, this)); }
class A;
class B;
class B
{
public:
void fn1(void (A::*fn)() )
{
//(*A::fn) ();how to call fn()?
}
};
class A
{
B *b;
public:
A():b(new B){}
void fn2()
{
cout<<"fn2"<<endl;
}
void fn3()
{
b->fn1(&A::fn2);
}
};
int main()
{
A a;
a.fn3();
}
I was asked this question in an interview: how to call fn2() from fn1(). That is what I am trying to solve. Can someone help me with that?
My main objective is to call fn2() from fn1(); if any other way is possible, please mention that
Pointers-to-member-functions need an object to call the function on.
The quickest change to your code is to simply pass in a pointer to the object you want to use. I assume that's the A that you called fn3 on.
So:
void fn1(void (A::*fn)(), A* ptr)
{
(ptr->*fn)(); // Yeah, the syntax is kind of weird
}
and:
void fn3()
{
b->fn1(&A::fn2, this);
}
(live demo)
In an interview I'd give this solution, then discuss how in modern C++ we'd prefer to have fn1 take a std::function (or a template callable), and bind the argument using std::bind or pass a lambda.
I'm writing a game code using C++. I want to bind the Child's member function into a delegate.
I want to use init_and_bind function like this simplified code:
class Parent {
protected:
Widget* widget;
};
class Child : public Parent {
public:
void foo() {
widget->init_and_bind(this, &Child::bar);
}
void bar() { /* do something */ }
};
I want to implement init_and_bind in Widget class, so I implemented like below code:
// pre-defined in engine
void Delegate::bind(Parent* object, void(Parent::* function)());
void Widget::init_and_bind(Parent* object, void(Parent::* function)()) {
init();
delegate->bind(object, function);
}
But it doesn't work. Because the init_and_bind's second parameter only accepts Parent's member functor type. So I can't pass Child's member functor. So I tried to use template and reinterpret_cast:
template<typename T>
void Widget::init_and_bind(Parent* object, void(T::* function)()) {
init();
delegate->bind(object, function); // error
delegate->bind(object, reinterpret_cast<void(Parent::*)()>(function); // error
}
But it also doesn't work. Because it is failed to cast the Child's functor to Parent's functor.
So, what type should be init_and_bind's second argument?
While the immediate solution is to static_cast, I think you shouldn't turn init_and_bind into a template. The generated code will always be the same pretty much. The only difference is possibly in how the actual cast is performed.
So you'll be getting a fair bit of code bloat, all because of a very small difference. I suggest you encapsulate that difference instead. Add a helper type to Widget for that:
class Widget {
struct MemFunc {
void(Parent::* function)();
template<class T>
MemFunc(void(T::* func)()) :
function(static_cast<void(Parent::*)()>(func))
{}
};
void init_and_bind(Parent* object, MemFunc mf) {
init();
delegate->bind(object, mf.function);
}
};
That way, only the very small piece of code that needs templating is in fact templated. What's best, it's happening transparently on the caller side. And it's probably not even going to cause any bloat. Because your original non-template version required the caller to static_cast anyway.
When creating a function for a class, should the parameter take a pointer to the class type and be invoked using 'this', or create a parameterless function and call it normally. Here is a demonstration:
class ExampleOne {
ExampleOne::ExampleOne() {
performAction(this);
}
void ExampleOne::performAction(ExampleOne *obj)
{
// Do something
}
}
class ExampleTwo {
ExampleTwo::ExampleTwo() {
performAction();
}
void ExampleTwo::performAction()
{
// Do something
}
}
In ExampleOne, the class functions are called with a pointer reference to itself. In ExampleTwo, functions are called without parameters.
I have seen both methods used in c++ code, and do not know which is the correct programming method.
The same question applies to working with the global instance variables, like this:
class ExampleThree {
ExampleThree::ExampleThree() {
Object *obj = new Object;
someFunction(obj);
}
ExampleThree::someFunction(Object *obj) {
// Do something
}
}
Or do we work with the instance variables rather than pointers to it:
class ExampleFour {
ExampleFour::ExampleFour() {
Object *obj = new Object;
someFunction();
}
ExampleFour::someFunction() {
// Do something with Obj instance
}
}
The reason this is done is code reuse, when some work done in the constructor can be used in other functions, if it can't then you should not make a separate function. And you shouldn't make the reuse function before there is a need.
The C++03 way
A {
A() {
Common(42);
}
A(int a) {
Common(a);
}
void Common(int c) {
... do something really complicated with c
}
}
The C++11 way
A {
A() : A(42) { // you can now call other constructors.
}
A(int a) {
... do something really complicated with c
}
}
Also in C++11 the move constructor and move assignment function mostly shares the same code (the latter has a return also) which could be reused.
The preferred way is to do everything in the initializer list for the constructor, which makes everything more safe. And only do something in the body if really needed.
C {
int dc;
C(int c) : dc(c) {
}
}
When you write something like this
MyClass myObject;
myObject.someFunction();
myObject is implicitly passed by reference to MyClass::someFunction, so you can access its attributes or methods by their names, without using the keyword this.
The usual way to use this is when you actually need a pointer or a reference to your object. For example, it is common when you overload operator=() to make it return a reference to the object with return *this;
I'm searching a solution for this for a few days now. Didn't find any question related enough to answer regrettably so here is my question.
Consider the next code:
// dummy class A
class A {
public:
void aFunction() { // <- this is the function I want to point at
cout << "aFunction() is called\n";
}
};
class B {
public:
template <class Class> // get a function pointer
void setFunction( void (Class::*func)() ) {
p_func = func;
}
void (*p_func)(); // the function pointer
}
int main() {
B obj;
objb.setFunction(&A::aFunction);
return 0;
}
I have a compilation error in setFunction() on p_func = func;:
cannot convert from 'void (__thiscall A::* )(void)' to 'void (__cdecl *)(void)'
And I don't seem to be able to get rid of it in any way. I know it has something to do with those invisible this pointers (__thiscall and __cdecl), but I don't know how to handle these. I tried making the member variable p_func a class template too (void (Class::*p_func)()) so it would have the same structure, but it that seems to be illegal to have 2 class templates in one class (why?), thus isn't the correct solution. This time the compiler complains about:
multiple template parameter lists are not allowed
This method (without the template) works perfectly on global functions (which is the workaround I currently use) and I saw the use of it in a library (sfgui), so it should be perfectly possible.
To have some context over why I'd want this: I'm trying to create a button. This button should be able to call whatever function I'd like. For now, I'd like it to call the start() function of an animation class I'm making.
p.s.: I know this example is useless since I can't run p_func: the function isn't static. I still need to add an object pointer (setFunction( void (Class::*func)(), Class* )), but that does not seem to be a problem. And I know about typedef to make a function pointer more readable, but not with a class template.
EDIT
After some more research I think the answer I need not the answer to this question, but rather another one. For once, I noticed that multiple template <class Class> is in fact allowed. However, it is not allowed on member variables since the compiler can't possibly know which class he'll need to use which probably is the reason for the error
multiple template parameter lists are not allowed
which is an odd description. Thanks anyway for the help, you did gave me a better insight.
You cannot convert a pointer-to-member Class::*func to a normal function pointer. They are of different types.
You should turn this:
void (*p_func)(); // the function pointer
into this:
void (class::*p_func)(); // the function pointer
You could also use a std::function<void()> and use boost::bind to bind it.
std::function<void()> fun = boost::bind(class::member_fun, args);
EDIT
What about making your B class a template so you can do this:
#include<iostream>
class A {
public:
void aFunction() { // <- this is the function I want to point at
std::cout << "aFunction() is called\n";
}
};
template<class T>
class B {
public:
void setFunction( void (T::*func)() ) {
p_func = func;
}
void (T::*p_func)(); // the function pointer
void callfunc()
{
(t.*p_func)(); //call pointer to member
}
private:
T t;
};
int main() {
B<A> obj;
obj.setFunction(&A::aFunction);
return 0;
}
Live Example
I found the complete answer myself while searching for a way to save *objects of an unknown type without using templates or void pointers which has been answered here. The solution is a bit dodgy, because you'll have to create a dummy parent which allows for certain conversions.
The idea is that you create a Parent and every object that is allowed to be pointed to must inherit from it. This way you can create a pointer as Parent *obj which can hold multiple types of objects, but of course only classes that inherit from Parent.
The same applies for function pointers. If you define your pointer as void (Parent::*func)() as member variable. You can ask the user a template function pointer template <class Class> setFunction( void (Class::*f)() ), which can hold any pointer to any class. Now you need to cast the function pointer to the desired class, Parent: static_cast<void(Parent::*)()>(f). Mind that this only works when Class inherits from Parent. Otherwise you'll get a compilation error.
Minimal Working Example
#include <iostream>
using namespace std;
// dummy class Parent
class Parent {};
// class A
class A : public Parent { // Mind the inheritance!
public:
A(int n) : num(n) {}
void print() { // <- function we want to point to
cout << "Number: " << num << endl;
}
int num;
}
// class B, will hold the 2 pointers
class B {
public:
B() {}
template <class Class> // will save the function and object pointer
void setFunction( void (Class::*func)(), Class *obj) {
function = static_cast<void(Parent::*)()>(func);
object = obj;
}
void execFunction() { // executes the function on the object
(object->*function)();
}
void (Parent::*function)(); // the function pointer
Parent *object; // the object pointer
}
int main() {
A a(5);
B b;
b.setFunction(&A::print, &a);
b.execFunction();
return 0;
}
I don't really like this solution. A better solution would be that class B could have a function where it returns a bool when the function needs to be executed. This way you could simply place an if statement in the main-function that executes the desired function.
A a(5);
B b;
while (;;) {
if (b.aTest())
a.print();
}
Where B::aTest() is declared as
bool B::aTest();
Hope this helps anyone that comes across the same problem. So it is perfectly possible but pretty dodgy in my opinion, and I don't encourage people using the first method.