从一个类返回一个函数

时间:2019-04-09 08:37:14

标签: c++ c++11

我希望能够从一个类中返回一个函数,这样我就不需要通过返回类型进行if-else了。

我有一个返回多个字符串的类。相反,我想返回多个函数。

#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;}

我想要的是:类handleMessage中的函数Handler返回某些内容,因此在我的主应用程序中,我不必使用if-else。

所以主体看起来像这样:

function = handle.handleMessage(0); 

应用程序将选择它将运行的功能。 例如:

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

7 个答案:

答案 0 :(得分:6)

有几种方法可以做到,最简单的方法是使用std::function。在此示例中,我们为每种情况返回一个lambda函数。您可以将其替换为刚编写的函数。

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 {
            ....
        }
    }
};

然后您的主要功能变为:

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

您可以用存储不同函数的数组替换swith / if case语句,就像注释中提到的那样。

如果您不想为使用std::function而支付额外的虚拟函数调用,则可以使用以下答案之类的别名,也可以仅使用auto关键字:

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 {
            ....
        }
    }
};

答案 1 :(得分:6)

您可以修改成员函数,使其返回函数指针,例如

using fptr = void (*)();

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

};

可以如下调用

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

请注意,上述if-else if-else分派并不理想。最好使用一个存储函数指针并将其与code关联的数据成员,例如使用std::unordered_map

请注意,当您将来需要返回有状态函数对象时,此方法将失败。然后,您需要使用std::function,它能够使用闭包或自定义类型包装带有operator()重载的lambda。

答案 2 :(得分:1)

std::function是功能强大的工具。弟弟是一个简单的函数指针。 我分别转换了MCVE以返回一个函数指针:

#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;}

输出:

1

Live Demo on coliru

答案 3 :(得分:1)

您可以使用return_type(*function_name)(argument_type1, argument_type2...)返回一个函数,这样的函数应类似于:

double f(int a, int b);

的名称为 double(*f)(int, int)

值得一提的是C++11's std::function,它需要<functional>标头。它具有更直观的用法: std::function<double(int, int)> ,但也增加了一些开销。

我还建议使用C++17's std::optional,就像变量code越界一样。此实现需要<optional>标头。

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
}

主要用途如下:

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

因为这样可以检查 func.has_value() ,这很方便。

答案 4 :(得分:1)

使用函数数组。

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

答案 5 :(得分:0)

您可以将int映射到函数或lambda,但请阅读befor at()的功能以及如果找不到键会发生的事情!

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)();

答案 6 :(得分:0)

我想提供没有任何if-else阻止的解决方案。您只需要模板化Handler::handleMessage函数。像这样:

// Class declaration
class Handler
{
private:

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

并使功能模板专门用于特定代码:

// 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;;
}

用法可能如下:

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