Passing functions as arguments in C++

回眸只為那壹抹淺笑 提交于 2020-02-03 08:10:44

问题


I'm a bit rusty in C++ and I'm switching after a year of python. Naturally I would like to translate the laziness coming from python to C++.

I just discovered rot13 and I'm all excited about it. I found 3 ways of doing it and I wanted to do a little performance test. I wanted to see also if there is a difference in modifying the string in place or creating a new one. So I ended up having 6 functions.

In the first method, I use a std::map to map the characters, thus I've built a class that initializes the map, in the second I use a ternary operator, and the third I use a bit shift.

Now the functions prototypes look like this

// 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){

I wanted to construct a function that accept those functions as arguments to then calculate the time and print the results

So I had a look at stackoverflow, 1, 2, and I came up with this

typedef void (*vfc)(string str);

void printtime_inplace(string title, vfc func){

I tried this construction yet this means I'm limited by the vfc return type which in my case is either void or string, and by the fact I need to pass the pointer of the class. Thus I will have to do 3 functions to accommodate the different functions, namely a function for the class member function, a function for the void return type and a function for the string return type.

So I asked myself, is this the case where I really need to use templates to not write 3 times the same function? I'm really not confident with templates but should I do 3 typedefs and structure the printtime function to accept a template? Moreover is there a way to tell the template you will accept only these types (namely the one I defined)?

An other question, is this let's say a good design? or would you suggest an other design? An other implementation?


回答1:


The easiest way, IMO, is to use a template instead of trying to write a function with a concrete type.

template<typename Function>
void printtime_inplace(string title, Function func)
{
    //...
    func(title);
    //...
}

This will now allow you to take anything that is a "function". You can pass it a regular function, a functor, a lambda, a std::function, basically, any callable. The compiler will stamp out different instantiations for you but as far as your code is concerned you are calling the same function.




回答2:


You can use std::function to provide such template:

#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;
}

See the live demo.



来源:https://stackoverflow.com/questions/45613214/passing-functions-as-arguments-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!