D
D
Daniil Demidko2016-06-07 08:35:28
C++ / C#
Daniil Demidko, 2016-06-07 08:35:28

Passing a function - templates or std::function?

I have a function that takes another function as one of its arguments - and both a lambda and a regular function can be passed.
I don't want to use function pointers, because they don't look good with lambdas and C++14 goodies.
Which is better to use -

template<typename Func> void MyFunc (const Func & otherFunc);

void MyFunc (const auto & otherFunc);
void MyFunc (const std::function<void()> & otherFunc);

void MyFunc (const void (&otherFunc)());?
Looked at similar situations in STL - templates are used there.
But why is the std::function class needed then?
Maybe still use a function reference?
What is the best way to pass functions in 2016?
spoiler

The function performs an action with a string - it takes a character, extracts substrings on both sides of the character, and inserts the result of the work of the passed function.
It works like this:
void Subcalc(
 std::string &line,
 const char &symbol, 
 const std::function<std::string(const std::string&, const std::string&)> 
 &mathFunc);

std::string s = " 5+5*3+1 ";

Subcalc ( s, '*', myMathFunc);    // s == "5+15+1"

Or like this:
std::string s = " 5+5*3-1 ";

Subcalc ( s, '*', myStringFunc);    // s == "5+555+1"

In general, I hesitate between options:
void Subcalc(
 std::string &line,
 const char &symbol, 
 const std::function<std::string(const std::string&, const std::string&)> 
 &mathFunc);

void Subcalc(
 std::string &line, const char &symbol, const auto &mathFunc);

template<typename Func>
void Subcalc(
 std::string &line,
 const char &symbol, 
 const Func &mathFunc);

void Subcalc(
 std::string &line,
 const char &symbol, 
 std::string (&mathFunc)(const std::string&, const std::string&));

What is the best option?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
Anton Zhilin, 2016-06-07
@Daniro_San

First option:
Ensures that otherFunc is inlined into MyFunc, which is the preferred option where maximum performance is required. But template functions cannot be virtual. That is, this option is very well suited for utility functions, and is poorly suited for public API methods and at module boundaries, since inline is not needed there, but virtuality and implementation hiding are needed.
Important note! The above code is not entirely correct, in such cases always use the transfer by universal reference:
This option covers both const functors and those that require mutability to work. If you plan to keep the functor, this also allows you to use perfect forwarding - in fact, the only way that works correctly with any functor passed:
Second option:
Can be used if you do not need a functor type. In fact, it is equivalent to the previous one.
Third option:
Take the negation of my previous arguments and apply here. Can be used with virtual functions, more suitable for API, but loses performance. Namely, calling otherFunc is equivalent to calling a virtual function.
Fourth option:
Works only with simple, globally defined functions. You should almost always use std::function instead.

K
kozura, 2016-06-07
@kozura

Probably, the old standard is maximally supported in STL, so there are templates.
std::function is more obvious, and lengthiness can be corrected by the conciseness of -typedef.
Too much versatility can be a problem, although it's more of a matter of taste.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question