我希望能够从一个类中返回一个函数,这样我就不需要通过返回类型进行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
答案 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
答案 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();
}
答案 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'