在 C++ 中将函数作为参数传递
Passing functions as arguments in C++
我对 C++ 有点生疏,我在 python 一年后转行。当然,我想将来自 python 的懒惰转化为 C++。
我刚刚发现 rot13,对此我非常兴奋。我找到了 3 种方法,我想做一点性能测试。
我还想看看就地修改字符串或创建新字符串是否有区别。所以我最终有 6 个函数。
在第一种方法中,我使用 std::map 来映射字符,因此我构建了一个 class 来初始化映射,在第二种方法中,我使用了三元运算符,并且第三,我使用位移位。
现在函数原型看起来像这样
// map dependent
void Rot13::convert_inplace(string& mystr){
string Rot13::convert(const string& mystr){
// ternary operator
void bitrot_inplace(string& mystr){
string bitrot(const string& mystr){
// bit shift
void bitshiftrot_inplace(string& mystr){
string bitshiftrot(const string& mystr){
我想构建一个接受这些函数作为参数的函数,然后计算时间并打印结果
所以我看了一下 Whosebug,1, 2,我想出了这个
typedef void (*vfc)(string str);
void printtime_inplace(string title, vfc func){
我尝试了这种构造,但这意味着我受到 vfc
return 类型的限制,在我的情况下是 void
或 string
,并且受事实上我需要传递 class 的指针。
因此,我将不得不执行 3 个函数来适应不同的函数,即 class 成员函数的函数、void return 类型的函数和字符串 return 类型的函数.
于是我问自己,这种情况下我真的需要使用模板而不是写3次相同的功能吗?我真的对模板没有信心,但我应该做 3 typedefs
并构造 printtime 函数以接受模板吗?此外,有没有办法告诉模板您将只接受这些类型(即我定义的类型)?
另外一个问题,这么说是不是一个好的设计?或者你会建议其他设计吗?另一个实现?
IMO,最简单的方法是使用模板而不是尝试编写具有具体类型的函数。
template<typename Function>
void printtime_inplace(string title, Function func)
{
//...
func(title);
//...
}
这将允许您拿走任何 "function"。您可以向它传递一个常规函数、一个函子、一个 lambda、一个 std::function
,基本上,任何可调用的。编译器将为您消除不同的实例化,但就您的代码而言,您正在调用相同的函数。
您可以使用std::function
提供这样的模板:
#include <iostream>
#include <functional>
#include <string>
#include <type_traits>
void convert_inplace(std::string& mystr){}
std::string convert(const std::string& mystr){
return mystr;
}
void bitrot_inplace(std::string& mystr){}
template<typename ret, typename par>
using fn = std::function<ret(par)>;
template<typename ret, typename par>
void caller(fn<ret,par> f) {
typename std::remove_reference<par>::type p;
ret r = f(p);
}
template<typename par>
void caller(fn<void,par> f) {
typename std::remove_reference<par>::type p;
f(p);
}
int main() {
auto f1 = fn<void,std::string&>(convert_inplace);
auto f2 = fn<std::string,const std::string&>(convert);
auto f3 = fn<void,std::string&>(bitrot_inplace);
caller(f1);
caller(f2);
caller(f3);
return 0;
}
参见live demo。
如果您想要一个带有可变参数的函数,这里是一个基于 user0042 的回答的示例(另请参阅 https://github.com/goblinhack/c-plus-plus-examples/blob/master/std_function_with_variadic_template/README.md)
#include <iostream>
int my_wrapped_function (int x, const std::string y)
{
std::cout << "SUCCESS: Hello from my_wrapped_function(x=" << x << ", y=" << y << ");" << std::endl;
return 43;
}
void my_argument_modifier (int &x)
{
std::cout << "SUCCESS: Hello from my_argument_modifier(x=" << x << ") => " << x + 1 << ";" << std::endl;
x++;
}
template<typename ret, typename T, typename... Rest>
using fn = std::function<ret(T, Rest...)>;
template<typename ret, typename T, typename... Rest>
ret wrapper(fn<ret, T, Rest...> f, T t, Rest... rest)
{
return f(t, rest...);
}
template<typename ret, typename T, typename... Rest>
ret wrapper(fn<ret, T&, Rest&...> f, T& t, Rest&... rest)
{
return f(t, rest...);
}
int main()
{
// Wrap a function with variable arguments
auto f1 = fn<int,int,const std::string>(my_wrapped_function);
auto result = wrapper(f1, 42, std::string("hello"));
// Result should be 43:
// Wrap a function that modifies its arguments
auto f2 = fn<void,int&>(my_argument_modifier);
wrapper(f2, result);
// Result should be 44:
return 0;
}
我对 C++ 有点生疏,我在 python 一年后转行。当然,我想将来自 python 的懒惰转化为 C++。
我刚刚发现 rot13,对此我非常兴奋。我找到了 3 种方法,我想做一点性能测试。 我还想看看就地修改字符串或创建新字符串是否有区别。所以我最终有 6 个函数。
在第一种方法中,我使用 std::map 来映射字符,因此我构建了一个 class 来初始化映射,在第二种方法中,我使用了三元运算符,并且第三,我使用位移位。
现在函数原型看起来像这样
// map dependent
void Rot13::convert_inplace(string& mystr){
string Rot13::convert(const string& mystr){
// ternary operator
void bitrot_inplace(string& mystr){
string bitrot(const string& mystr){
// bit shift
void bitshiftrot_inplace(string& mystr){
string bitshiftrot(const string& mystr){
我想构建一个接受这些函数作为参数的函数,然后计算时间并打印结果
所以我看了一下 Whosebug,1, 2,我想出了这个
typedef void (*vfc)(string str);
void printtime_inplace(string title, vfc func){
我尝试了这种构造,但这意味着我受到 vfc
return 类型的限制,在我的情况下是 void
或 string
,并且受事实上我需要传递 class 的指针。
因此,我将不得不执行 3 个函数来适应不同的函数,即 class 成员函数的函数、void return 类型的函数和字符串 return 类型的函数.
于是我问自己,这种情况下我真的需要使用模板而不是写3次相同的功能吗?我真的对模板没有信心,但我应该做 3 typedefs
并构造 printtime 函数以接受模板吗?此外,有没有办法告诉模板您将只接受这些类型(即我定义的类型)?
另外一个问题,这么说是不是一个好的设计?或者你会建议其他设计吗?另一个实现?
IMO,最简单的方法是使用模板而不是尝试编写具有具体类型的函数。
template<typename Function>
void printtime_inplace(string title, Function func)
{
//...
func(title);
//...
}
这将允许您拿走任何 "function"。您可以向它传递一个常规函数、一个函子、一个 lambda、一个 std::function
,基本上,任何可调用的。编译器将为您消除不同的实例化,但就您的代码而言,您正在调用相同的函数。
您可以使用std::function
提供这样的模板:
#include <iostream>
#include <functional>
#include <string>
#include <type_traits>
void convert_inplace(std::string& mystr){}
std::string convert(const std::string& mystr){
return mystr;
}
void bitrot_inplace(std::string& mystr){}
template<typename ret, typename par>
using fn = std::function<ret(par)>;
template<typename ret, typename par>
void caller(fn<ret,par> f) {
typename std::remove_reference<par>::type p;
ret r = f(p);
}
template<typename par>
void caller(fn<void,par> f) {
typename std::remove_reference<par>::type p;
f(p);
}
int main() {
auto f1 = fn<void,std::string&>(convert_inplace);
auto f2 = fn<std::string,const std::string&>(convert);
auto f3 = fn<void,std::string&>(bitrot_inplace);
caller(f1);
caller(f2);
caller(f3);
return 0;
}
参见live demo。
如果您想要一个带有可变参数的函数,这里是一个基于 user0042 的回答的示例(另请参阅 https://github.com/goblinhack/c-plus-plus-examples/blob/master/std_function_with_variadic_template/README.md)
#include <iostream>
int my_wrapped_function (int x, const std::string y)
{
std::cout << "SUCCESS: Hello from my_wrapped_function(x=" << x << ", y=" << y << ");" << std::endl;
return 43;
}
void my_argument_modifier (int &x)
{
std::cout << "SUCCESS: Hello from my_argument_modifier(x=" << x << ") => " << x + 1 << ";" << std::endl;
x++;
}
template<typename ret, typename T, typename... Rest>
using fn = std::function<ret(T, Rest...)>;
template<typename ret, typename T, typename... Rest>
ret wrapper(fn<ret, T, Rest...> f, T t, Rest... rest)
{
return f(t, rest...);
}
template<typename ret, typename T, typename... Rest>
ret wrapper(fn<ret, T&, Rest&...> f, T& t, Rest&... rest)
{
return f(t, rest...);
}
int main()
{
// Wrap a function with variable arguments
auto f1 = fn<int,int,const std::string>(my_wrapped_function);
auto result = wrapper(f1, 42, std::string("hello"));
// Result should be 43:
// Wrap a function that modifies its arguments
auto f2 = fn<void,int&>(my_argument_modifier);
wrapper(f2, result);
// Result should be 44:
return 0;
}