提问人:ModernEraCaveman 提问时间:7/6/2023 更新时间:7/6/2023 访问量:65
是否可以将函数作为参数重载运算符?
Is it possible to overload an operator with a function as a parameter?
问:
我刚刚发现了操作员超载,我只是对它感到高兴。在测试它的用途时,我遇到了一个我似乎无法工作的案例,而且我找不到合适的资源来解决。
我正在尝试重载一个运算符,该运算符将函数作为参数。我的目标是创建一个可以执行给定的任何功能的结构(在合理范围内,例如遵循相同一般结构的提交命令)。在这种情况下,传递 or 不起作用,因为运算符的内部操作将包含一个 execute 函数。如果 or 没有匹配的成员函数,则该操作将不起作用。如在以下情况下:struct
class
struct
class
struct s_test1 {
void funcA() {}
}
struct s_test2 {
void funcB() {}
}
struct s_doer {
friend void operator<<(auto, auto& s_input){
s_input.funcA(); // would fail for s_test2
s_input.funcB(); // would fail for s_test1
}
}
最终,我想创建类似这个伪代码的东西:
void func0(int& storage) { storage = 0; }
void func1(int& storage) { storage = 1; }
void func2(int& storage) { storage = 2; }
void alt_func(int& storage, int alt) { storage = alt; }
struct s_doer {
friend void operator<<(auto, void(*func)()){
int storage;
func(storage);
cout << storage << endl; // to check if it worked, idk
}
}
int main() {
s_doer{} << func0();
s_doer{} << func1();
s_doer{} << alt_func(); // alternatively 's_doer << alt_func(), 0' where '0' is the alt parameter of 'alt_func'
}
这是我目前的实施尝试:
struct s_doer {
friend void operator<<(auto, void (*func)()) {
std::cout << "test" << std:endl;
func();
std::cout << "test" << std::endl;
}
};
struct s_informer {
s_informer(int n) {
info = n;
}
void inform() {
std::cout << info << std::endl;
}
private:
int info;
friend void operator<<(auto, const void (*func)());
};
s_informer informer(2);
int main() {
s_doer{} << informer.inform();
}
我似乎无法通过错误。no operator "<<" matches these operands
我的其他一些尝试是:
friend void operator<<(auto, std::function<void()> func) {...}
template<typename input>
using Func = void(*)(input in);
friend void operator<<(auto, Func func) {...}
typedef void (*Func)(int n);
friend void operator<<(auto, Func func) {...}
是否可以使操作员过载功能输入?是否可以在重载期间为函数指定参数?
怎么做?
答:
informer.inform()
立即调用该函数,而您希望将调用延迟到 。operator<<
您可以传递一个调用它的 lambda,然后在 中调用它。operator<<
#include <functional>
#include <iostream>
struct s_doer
{
template <typename F>
friend void operator<<(s_doer, F &&func)
{
std::cout << "test\n";
std::forward<F>(func)();
std::cout << "test\n";
}
};
struct s_informer
{
s_informer(int n)
{
info = n;
}
void inform()
{
std::cout << info << std::endl;
}
private:
int info;
};
s_informer informer(2);
int main()
{
s_doer{} << []{informer.inform();};
}
请注意,我已经更改了要模板化的第二个参数,否则您将无法接受捕获 lambda(这有利于通用性,尽管此特定 lambda 未捕获)。operator<<
我还将第一个参数从 更改为 .前者虽然聪明,但可能会产生意想不到的副作用:auto
s_doer
template <typename> struct A {};
int main()
{
A<s_doer>{} << []{informer.inform();}; // This actually compiles! But you don't want it to.
}
评论
A<s_doer>{} << []{informer.inform();};
alt_func
需要两个参数,并且不清楚应该传递给该函数的参数。但是,如果我们忽略这一点,那么你的第一次尝试就非常接近了。operator<<
friend void operator<<(auto, void(*func)())
应该是.您肯定希望尽可能多地指定合理内容,这就是您要在左侧使用的原因。右侧采用指向函数的指针,这些函数各自接受一个参数,并返回 void,因此您必须指定参数。friend void operator<<(s_doer&&, void(*func)(int&))
s_doer&&
int&
int&
然后在调用的时候,你不想传递func0的结果,所以你不想调用它,所以你不想输入。相反,您希望传递函数本身:operator<<
func0()
s_doer{} << func0;
struct s_doer {
friend void operator<<(s_doer&&, void(*func)(int&)){
int storage;
func(storage);
cout << storage << endl; // to check if it worked, idk
}
};
int main() {
s_doer{} << func0;
s_doer{} << func1;
//s_doer{} << alt_func; // alternatively 's_doer << alt_func(), 0' where '0' is the alt parameter of 'alt_func'
}
http://coliru.stacked-crooked.com/a/e215b7629acf8a76
让一个接受具有任何签名的函数的参数几乎永远没有意义,因为没有办法调用它,因为你不知道要传递哪些参数。 因此它是无用的。但如果需要,您可以使用模板。
template<class...Args>
void operator<<(s_doer&&, void(*func)(Args&&...)) {
func(std::forward<Args>(values)...);
//not sure where you plan to get `values` from, but there's ways
}
另请注意,编译器很难优化函数指针,因此我们经常避免使用它们并允许函数类型本身作为模板参数,从而允许函数类类,例如等。这些可能会导致二进制膨胀,但也更容易优化。std::less
评论
operator<<
使用 >2 参数将无法编译。
s_doer{} << alt_func, 2;
我正在抛出一个替代方案,它构建了 s 的 a,并在完整表达式的末尾调用所有收集的函数。对于需要参数的函数,您可以将它们打包到 lambda 中。std::tuple
std::function
#include <functional>
#include <iostream>
#include <tuple>
#include <utility>
template <class T = std::tuple<>>
struct s_doer {
~s_doer() {
// time to die, call the collected functions:
std::apply([](auto&&... funcs) { ((funcs ? funcs() : void()), ...); }, t);
}
T t;
template <class F>
friend auto operator<<(s_doer&& d, F&& f) {
std::function func{std::forward<F>(f)};
auto tc = std::tuple_cat(std::move(d.t), std::tuple{std::move(func)});
// return a new s_doer with the collected functions so far
return s_doer<decltype(tc)>{std::move(tc)};
}
};
int main() {
s_doer{} << [] { std::cout << "Hello\n"; } << [] { std::cout << "fab\n"; };
}
输出:
Hello
fab
没有 s 的更轻量级版本:std::function
template <class T = std::tuple<>>
struct s_doer {
~s_doer() {
// time to die, call the collected functions:
if (last) std::apply([](auto&&... funcs) { (..., funcs()); }, t);
}
T t;
bool last = false;
template <class F>
friend auto operator<<(s_doer&& d, F&& f) {
auto tc = std::tuple_cat(std::move(d.t), std::tuple{std::forward<F>(f)});
d.last = false;
// return a new s_doer with the collected functions so far
return s_doer<decltype(tc)>{std::move(tc), true};
}
};
评论
alt_func
需要两个参数,并且不清楚应该传递给该函数的参数operator<<