【发布时间】:2020-11-03 15:56:54
【问题描述】:
尊敬的 Stackoverflow 社区,
我对 c++ 还很陌生,而且我一直在摸索,还没有找到解决问题的方法。一段时间以来,我一直在寻找和尝试一些事情,并且已经到了提出问题会更有益和更有教育意义的地步。
问题:
我想创建一个类或函数来包装/装饰带有或不带参数的给定函数。 就像 python 或 c# 等中的老式 @wrapthis 一样。
到目前为止,我发现的最接近的东西(即优雅、简短且易于使用)来自这个 stackoverflow 答案:C++ Equivalent Decorator
挠头部分正在尝试传递指针函数。我收到的错误:
Error (active) E0300 a pointer to a bound function may only be used to call the function
这显然意味着不允许以这种方式传递指针,那么我在这里有什么选择?
作为答案的工作示例会很棒!
下面是我想要实现的示例:
Something.h
class Something
{
private:
public:
Something() {}
void v_func_with_nothing() { std::cout << "v_func_with_nothing" << "\n"; }
void v_func_with_void(void) { std::cout << "v_func_with_void" << "\n"; }
void v_func_with_one_arg(int x) { std::cout << "v_func_with_one_arg" << x << " " << "\n"; }
void v_func_with_args(int x, int y) { std::cout << "v_func_with_args" << x << " " << y << "\n"; }
int return_func_with_nothing() { return 1; }
int return_func_with_void(void) { return 3; }
int return_func_with_one_arg(int x) { return x; }
int return_func_with_args(int x, int y) { return x+y; }
};
Decorator.h [再次来源:C++ Equivalent Decorator]
template<typename T>
auto decorator(T&& func)
{
auto new_function = [func = std::forward<T>(func)](auto&&... args)
{
std::cout << "BEGIN decorating...\n";
auto result = func(std::forward<decltype(args)>(args)...);
std::cout << "END decorating\n";
return result;
};
return new_function;
}
main.cpp
#include <iostream>
#include "Something.h"
#include "Decorator.h"
int main()
{
Something* something = new Something();
auto somedeco = decorator(&something->return_func_with_one_arg);//<-- error here in argument
//int value = somedeco(**enter an argument**);
//std::cout << value << "\n";
return 0;
}
谢谢!
编辑:解决方案
根据下面给出的友好答案,我想用一个例子来编辑这篇文章。问题的解决方案是使用 lambda。
Decorator.h:我创建了 2 个装饰器(一个用于返回函数,一个用于 void 函数):
template<typename T>
auto DECO_R(T&& func)
{
try
{
auto new_function = [func = std::forward<T>(func)](auto&&... args)
{
std::cout << "BEGIN RETURN decorating...\n";
auto result = func(std::forward<decltype(args)>(args)...);
std::cout << "END RETURN decorating\n";
return result;
};
return new_function;
}
catch (const std::exception& ex)
{
std::cout << ex.what() << "\n";
}
}
template<typename T>
auto DECO_V(T&& func)
{
try
{
auto new_function = [func = std::forward<T>(func)](auto&&... args)
{
std::cout << "BEGIN VOID decorating...\n";
func(std::forward<decltype(args)>(args)...);
std::cout << "END VOID decorating\n";
};
return new_function;
}
catch (const std::exception& ex)
{
std::cout << ex.what() << "\n";
}
}
Main.cpp:2 个示例
int main()
{
Something* something = new Something();
auto somedeco = DECO_R(
[&](int x) {
return something->return_func_with_one_arg(x);
});
int value = somedeco(255);
std::cout << value << "\n";
auto some_v_deco = DECO_V(
[&](int x) {
return something->v_func_with_one_arg(x);
});
some_v_deco(2);
return 0;
}
输出
开始返回装饰...
END RETURN 装修
255
开始 VOID 装饰...
v_func_with_one_arg2
END VOID装饰
我希望这可以帮助其他人。
【问题讨论】:
-
你需要一个对象来调用一个成员函数。现在有几个选择:是要将实例包装到
somedeco中,还是somedeco在调用时应将实例作为参数? -
@idclev463035818 不是我的对象的“东西”吗?但是要回答您的问题,可能会将实例包装到 somedeco 中?因为从视觉角度来看,知道它返回的数据类型有点不清楚。不管怎样,你有什么建议?
-
对象中的函数是静态的,它们没有不同的每个对象指针。
-
@MichaelChourdakis 非静态成员函数可以,即
this,但要做到这一点,您必须首先进入函数,这需要首先在给定实例上调用它;-)我认为您的观点是获取指向成员函数的指针的语法宁愿是&Something::return_func_with_one_arg,即指针本身没有附加实例,需要在调用时提供。 -
另外,正如@idclev463035818 指出的那样,
new在这里没有合法用途。更喜欢auto something = Something{};
标签: c++ pointers decorator function-pointers wrapper