JeanClarity
JeanClarity

Reputation: 61

Return a function from a class

I want to be able to return a function from a class, so that I do not need to if-else through a return type.

I have a class that returns multiple strings. Instead, I want to return multiple functions.

#include <iostream>

class Handler
{
private:

public:
    int handleMessage(int code)
    {
        return code+1;
    }

};

void func1();
void func2();
void func3();

int main (int argc, char *argv[])
{
    Handler handle;
    int code = handle.handleMessage(0);
    if(code == 1)
    {
        func1();
    }
    return 0;
}

void func1(){ std::cout << "1" << std::endl;}
void func2(){ std::cout << "2" << std::endl;}
void func3(){ std::cout << "3" << std::endl;}

What I want is: That the function handleMessage in the class Handler returns something so that in my main application I do not have to use if-else.

So the main looks like this:

function = handle.handleMessage(0); 

And the application will choose which function it will run. for example:

function = handle.handleMessage(0);  //will run func1 
function = handle.handleMessage(1);  //will run func2

Upvotes: 6

Views: 399

Answers (7)

Khurshid Normuradov
Khurshid Normuradov

Reputation: 906

Use an array of functions.

void func1(){  std::cout << "1" << std::endl; } 
void func2(){  std::cout << "2" << std::endl; } 
void func3(){  std::cout << "3" << std::endl; } 

typedef void (* func ) () ;

class Handler { 
  public:
      func handleMessage(int code)const{  
            static const func  F[] = { func1, func2, func3 };
            return F[ code ];
       }
};

int main() 
{
     Handler handler;
     func f = handler.handleMessage(0); // returns func1
     f();
}

live example

Upvotes: 1

vahancho
vahancho

Reputation: 21258

I would like to offer solution without any if-else block. You just need to templatize your Handler::handleMessage function. Something like this:

// Class declaration
class Handler
{
private:

public:
  template<int code>
  void handleMessage();
};

and specialize the function template for particular codes:

// Function template specializations.
template<>
void Handler::handleMessage<1>()
{
  std::cout << "1" << std::endl;
}
template<>
void Handler::handleMessage<2>()
{
  std::cout << "2" << std::endl;;
}
template<>
void Handler::handleMessage<3>()
{
  std::cout << "3" << std::endl;;
}

// All cases, except 1, 2 and 3
template<int code>
void Handler::handleMessage()
{
  std::cout << "Anything else" << std::endl;;
}

The usage may look like:

Handler h;
h.handleMessage<1>();   // Prints 1
h.handleMessage<2>();   // Prints 2
h.handleMessage<3>();   // Prints 3
h.handleMessage<323>(); // Prints 'Anything else'

Upvotes: 0

Stack Danny
Stack Danny

Reputation: 8166

You can return a function with return_type(*function_name)(argument_type1, argument_type2...) so a function that looks like:

double f(int a, int b);

has the name double(*f)(int, int).

Worth mentioning is C++11's std::function which requires the <functional> header. It has a more intuitive usage: std::function<double(int, int)> but also adds a bit of overhead.

I would also like to suggest the usage of C++17's std::optional as for the case when the variable code goes out of bounds. This implementation requires the <optional> header.

std::optional<void(*)()> handleMessage(int code){
    switch (code) {
    case 0: return std::optional(func1);
    case 1: return std::optional(func2);
    case 2: return std::optional(func3);
    }
    return std::nullopt; //empty
}

usage in main looks like the following:

Handler handle;
auto func = handle.handleMessage(0);
if (func.has_value()) {
    func.value()();
}

as this allows to check if func.has_value() which is quite convenient.

Upvotes: 1

mohabouje
mohabouje

Reputation: 4050

There are several ways to do so, the simplest one, you can use an std::function. In this example we returning a lambda function for each case. You can replace it with the functions you just wrote.

class Handler {
public:
    std::function<void()> handleMessage(int code) {
        code = code + 1; // ++code or whatever
        if (code == X) {
            return []() { std::cout << "Cool! I'am x!" << std::endl; };
        } else if (code == Y) {
            return []() { std::cout << "Cool! I'am x!" << std::endl; };
        } else if (...) {
            ...
        } else {
            ....
        }
    }
};

Then your main function becomes:

int main (int argc, char *argv[]) {
    Handler handle;
    const auto func = handle.handleMessage(0);
    func();
    return 0;
}

You can replace the swith/if case statement by an array storing the different functions, like they mentioned in the comments.

If you dont want to pay the extra virtual function call regarding the usage of an std::function, you can use an alias like the answer below or just the auto keyword:

class Handler {
public:
    constexpr auto handleMessage(int code) {
        code = code + 1; // ++code or whatever
        if (code == X) {
            return &func1;
        } else if (code == Y) {
            return &func2;
        } else if (...) {
            ...
        } else {
            ....
        }
    }
};

Upvotes: 6

you can map the ints to a function or lambda, but read befor what at() does and what happens if the key is not found!!

void function1()
{
    std::cout << "q1" << std::endl;
}
void function2()
{
    std::cout << "q2" << std::endl;
}

int main(int argc, char* argv[])
{
    std::map<int, std::function<void(void)>> map;
    map.insert(std::make_pair(1, function1));
    map.insert(std::make_pair(1, function2));
    map.at(1)();

Upvotes: 0

Scheff&#39;s Cat
Scheff&#39;s Cat

Reputation: 20171

std::function is a powerful tool. The tiny brother is a simple function pointer. I transformed MCVE respectively to return a function pointer:

#include <iostream>

typedef void (*FuncPtr)();

void func1();
void func2();
void func3();
void funcError();

class Handler
{
private:

public:
    FuncPtr handleMessage(int code)
    {
      switch (code + 1) {
        case 1: return &func1;
        case 2: return &func2;
        case 3: return &func3;
        default: return &funcError;
      }
    }

};

int main (int argc, char *argv[])
{
    Handler handle;
    FuncPtr pFunc = handle.handleMessage(0);
    pFunc();
    return 0;
}

void func1(){ std::cout << "1" << std::endl;}
void func2(){ std::cout << "2" << std::endl;}
void func3(){ std::cout << "3" << std::endl;}
void funcError(){ std::cout << "ERROR!" << std::endl;}

Output:

1

Live Demo on coliru

Upvotes: 1

lubgr
lubgr

Reputation: 38325

You can modify the member function such that it returns a function pointer, e.g.

using fptr = void (*)();

struct Handler
{
    fptr handleMessage (int code)
    {
       if (code == 0)
          return &func1;
       else if (code == 1)
          return &func2;
       else
          return &func3;
    }

};

This can be invoked as follows

 Handler handle;
 auto f = handle.handleMessage(0);
 f();

Note that the above if-else if-else dispatch isn't ideal. Prefer a data member that stores the function pointers and associates them with a code, e.g. using a std::unordered_map.

Note that when you need to return stateful function objects in the future, this approach will fail. Then, you need to embrace std::function which is able to wrap lambdas with closures or custom types with an operator() overload.

Upvotes: 6

Related Questions