在 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 类型的限制,在我的情况下是 voidstring,并且受事实上我需要传递 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;
}