将另一个 class 的成员函数传递给 std::function 参数
Passing a member function of another class into a std::function parameter
我有一个 class,其函数接受 std::function
并存储它。这部分似乎可以编译(但如果有任何问题请指出)
#include <functional>
#include <iostream>
struct worker
{
std::function<bool(std::string)> m_callback;
void do_work(std::function<bool(std::string)> callback)
{
m_callback = std::bind(callback, std::placeholders::_1);
callback("hello world\n");
}
};
// pretty boring class - a cut down of my actual class
struct helper
{
worker the_worker;
bool work_callback(std::string str)
{
std::cout << str << std::endl;
return true;
}
};
int main()
{
helper the_helper;
//the_helper.the_worker.do_work(std::bind(&helper::work_callback, the_helper, std::placeholders::_1)); // <---- SEGFAULT (but works in minimal example)
the_helper.the_worker.do_work(std::bind(&helper::work_callback, &the_helper, std::placeholders::_1)); // <---- SEEMS TO WORK
}
我得到一个 segfault,但我不确定为什么。我以前用过这个,事实上,我从另一个地方复制了这个例子我用过它。成员函数是我调用它的 class 的一部分的唯一真正区别(即 this
而不是 the_helper
)。
所以这就是为什么我也想问我是否还有其他一般性错误?就像我应该将 std::function
传递为:
void do_work(std::function<bool(std::string)>&& callback)
或
void do_work(std::function<bool(std::string)>& callback)
@Rakete1111 在评论中也指出,问题可能出在这段代码中:
bool work_callback(std::string str)
{
std::cout << str << std::endl;
}
在 C++ 中,如果非 void 函数没有 return 值,则结果是未定义的行为。
此示例将因 clang but pass with gcc 而崩溃。
如果 helper::work_callback
returns(例如,true
),代码只工作 fine.
我不知道为什么你的代码段错误,因为我被宠坏了,直接跳过 std::bind
到 lambda。因为你使用 C++11
你真的应该将你的代码从 std::bind
转换为 lambdas:
struct worker
{
std::function<bool(std::string)> m_callback;
void do_work(std::function<bool(std::string)> callback)
{
m_callback = callback;
callback("hello world\n");
}
};
现在 work_callback
和调用 do_work
需要一些分析。
第一个版本:
struct helper
{
worker the_worker;
bool work_callback(std::string)
{
return false;
}
};
int main()
{
helper the_helper;
the_helper.the_worker.do_work([&](std::string s) { return the_helper.work_callback(s); });
}
现在这个版本适用于您的玩具示例。但是在野外你需要小心。传递给 do_work
然后存储在 the_worker
中的 lambda 通过引用捕获 the_helper
。这意味着仅当作为对 lambda 的引用传递的 helper
对象比存储 m_callback
的 worker
对象存在时间更长时,此代码才有效。在您的示例中,worker
对象是 helper
class 的子对象,因此这是正确的。但是,如果在您的真实示例中情况并非如此,或者您无法证明这一点,那么您需要按值捕获。
第一次尝试按值捕获(不编译):
struct helper
{
worker the_worker;
bool work_callback(std::string)
{
return false;
}
};
int main()
{
helper the_helper;
the_helper.the_worker.do_work([=](std::string s) { return the_helper.work_callback(s); });
}
这不会编译,因为存储在 lambda 对象中的 the_helper
的副本默认为 const
,因此您不能对其调用 work_callback
。
如果不能使 work_callback
const 有问题的解决方案是使 lambda mutable
:
struct helper
{
worker the_worker;
bool work_callback(std::string)
{
return false;
}
};
int main()
{
helper the_helper;
the_helper.the_worker.do_work([=](std::string s) mutable { return the_helper.work_callback(s); });
}
但是你需要考虑这是否是你想要的。
更有意义的是使 work_callback
const:
struct helper
{
worker the_worker;
bool work_callback(std::string) const
{
return false;
}
};
int main()
{
helper the_helper;
the_helper.the_worker.do_work([=](std::string s) { return the_helper.work_callback(s); });
}
获得SEGFAULT
的原因已经在评论中提到了。
但是,我想指出的是,你需要使用 neither std::bind
nor std::function
,在你给定的情况下。相反,只需拥有一个 lambda and a function pointer,您就可以处理您打算做的事情。
struct worker
{
typedef bool(*fPtr)(const std::string&); // define fun ptr type
fPtr m_callback;
void do_work(const std::string& str)
{
// define a lambda
m_callback = [](const std::string& str)
{
/* do something with string*/
std::cout << "Call from worker: " << str << "\n";
return true;
};
bool flag = m_callback(str);// just call the lambda here
/* do some other stuff*/
}
};
struct helper
{
worker the_worker;
bool work_callback(const std::string& str)
{
std::cout << "Call from helper: ";
this->the_worker.do_work(str);
return true; ------------------------>// remmeber to keep the promise
}
};
用例为:
int main()
{
helper the_helper;
the_helper.work_callback(std::string("hello world"));
// or if you intend to use
the_helper.the_worker.do_work(std::string("hello world"));
return 0;
}
参见Output here:
PS:在上面的例子中,如果worker
对于后面的情况不需要m_callback
(即只对do_work()
), 然后你可以删除这个成员,因为可以在声明它的地方创建和调用 lambdas。
struct worker
{
void do_work(const std::string& str)
{
bool flag = [](const std::string& str)->bool
{
/* do something with string*/
std::cout << "Call from worker: " << str << "\n";
return true;
}(str); -------------------------------------> // function call
/* do other stuff */
}
};
我有一个 class,其函数接受 std::function
并存储它。这部分似乎可以编译(但如果有任何问题请指出)
#include <functional>
#include <iostream>
struct worker
{
std::function<bool(std::string)> m_callback;
void do_work(std::function<bool(std::string)> callback)
{
m_callback = std::bind(callback, std::placeholders::_1);
callback("hello world\n");
}
};
// pretty boring class - a cut down of my actual class
struct helper
{
worker the_worker;
bool work_callback(std::string str)
{
std::cout << str << std::endl;
return true;
}
};
int main()
{
helper the_helper;
//the_helper.the_worker.do_work(std::bind(&helper::work_callback, the_helper, std::placeholders::_1)); // <---- SEGFAULT (but works in minimal example)
the_helper.the_worker.do_work(std::bind(&helper::work_callback, &the_helper, std::placeholders::_1)); // <---- SEEMS TO WORK
}
我得到一个 segfault,但我不确定为什么。我以前用过这个,事实上,我从另一个地方复制了这个例子我用过它。成员函数是我调用它的 class 的一部分的唯一真正区别(即 this
而不是 the_helper
)。
所以这就是为什么我也想问我是否还有其他一般性错误?就像我应该将 std::function
传递为:
void do_work(std::function<bool(std::string)>&& callback)
或
void do_work(std::function<bool(std::string)>& callback)
@Rakete1111 在评论中也指出,问题可能出在这段代码中:
bool work_callback(std::string str)
{
std::cout << str << std::endl;
}
在 C++ 中,如果非 void 函数没有 return 值,则结果是未定义的行为。
此示例将因 clang but pass with gcc 而崩溃。
如果 helper::work_callback
returns(例如,true
),代码只工作 fine.
我不知道为什么你的代码段错误,因为我被宠坏了,直接跳过 std::bind
到 lambda。因为你使用 C++11
你真的应该将你的代码从 std::bind
转换为 lambdas:
struct worker
{
std::function<bool(std::string)> m_callback;
void do_work(std::function<bool(std::string)> callback)
{
m_callback = callback;
callback("hello world\n");
}
};
现在 work_callback
和调用 do_work
需要一些分析。
第一个版本:
struct helper
{
worker the_worker;
bool work_callback(std::string)
{
return false;
}
};
int main()
{
helper the_helper;
the_helper.the_worker.do_work([&](std::string s) { return the_helper.work_callback(s); });
}
现在这个版本适用于您的玩具示例。但是在野外你需要小心。传递给 do_work
然后存储在 the_worker
中的 lambda 通过引用捕获 the_helper
。这意味着仅当作为对 lambda 的引用传递的 helper
对象比存储 m_callback
的 worker
对象存在时间更长时,此代码才有效。在您的示例中,worker
对象是 helper
class 的子对象,因此这是正确的。但是,如果在您的真实示例中情况并非如此,或者您无法证明这一点,那么您需要按值捕获。
第一次尝试按值捕获(不编译):
struct helper
{
worker the_worker;
bool work_callback(std::string)
{
return false;
}
};
int main()
{
helper the_helper;
the_helper.the_worker.do_work([=](std::string s) { return the_helper.work_callback(s); });
}
这不会编译,因为存储在 lambda 对象中的 the_helper
的副本默认为 const
,因此您不能对其调用 work_callback
。
如果不能使 work_callback
const 有问题的解决方案是使 lambda mutable
:
struct helper
{
worker the_worker;
bool work_callback(std::string)
{
return false;
}
};
int main()
{
helper the_helper;
the_helper.the_worker.do_work([=](std::string s) mutable { return the_helper.work_callback(s); });
}
但是你需要考虑这是否是你想要的。
更有意义的是使 work_callback
const:
struct helper
{
worker the_worker;
bool work_callback(std::string) const
{
return false;
}
};
int main()
{
helper the_helper;
the_helper.the_worker.do_work([=](std::string s) { return the_helper.work_callback(s); });
}
获得SEGFAULT
的原因已经在评论中提到了。
但是,我想指出的是,你需要使用 neither std::bind
nor std::function
,在你给定的情况下。相反,只需拥有一个 lambda and a function pointer,您就可以处理您打算做的事情。
struct worker
{
typedef bool(*fPtr)(const std::string&); // define fun ptr type
fPtr m_callback;
void do_work(const std::string& str)
{
// define a lambda
m_callback = [](const std::string& str)
{
/* do something with string*/
std::cout << "Call from worker: " << str << "\n";
return true;
};
bool flag = m_callback(str);// just call the lambda here
/* do some other stuff*/
}
};
struct helper
{
worker the_worker;
bool work_callback(const std::string& str)
{
std::cout << "Call from helper: ";
this->the_worker.do_work(str);
return true; ------------------------>// remmeber to keep the promise
}
};
用例为:
int main()
{
helper the_helper;
the_helper.work_callback(std::string("hello world"));
// or if you intend to use
the_helper.the_worker.do_work(std::string("hello world"));
return 0;
}
参见Output here:
PS:在上面的例子中,如果worker
对于后面的情况不需要m_callback
(即只对do_work()
), 然后你可以删除这个成员,因为可以在声明它的地方创建和调用 lambdas。
struct worker
{
void do_work(const std::string& str)
{
bool flag = [](const std::string& str)->bool
{
/* do something with string*/
std::cout << "Call from worker: " << str << "\n";
return true;
}(str); -------------------------------------> // function call
/* do other stuff */
}
};