Using std::bind in template function parameter - c++

This has probably been asked in some way before, but I cannot find the right search keywords.
While writing testing functions, I decided to refactor the testing code into a template function:
#include <iostream>
#include <functional>
#include <utility>
#include <vector>
template <typename In, typename Exp >
void runTest (
std::pair<In, Exp> testParams,
Exp (*testFunction)(In)
/*std::function< Exp(In)> testFunction */ )
{
Exp result = testFunction(testParams.first);
std::cout << "Result : " << (result == testParams.second? "SUCCESS":"FAILURE")
<< " expected : " << testParams.second
<< " got : " << result
<< std::endl;
}
Fill a vector with input and expected results and pass the pairs along with the function we want to test. Worked great for one function:
long f1 (long a1)
{
return a1 + 100;
}
void testf1()
{
std::vector<std::pair<long, long> > testCases = {
{100,200},
{300,400}
};
for (auto test : testCases) {
runTest (test, f1);
}
}
but then had to test one that takes two parameters. "Ok, no problem, I'll std::bind1st... oh, that's deprecated... std::bind should to it though, right? the first argument and pass that along to runTest"...
long f2 (long a1, long a2)
{
return a1+a2;
}
void testf2()
{
long a1 = 1234;
std::vector<std::pair<long, long> > testCases = {
{0,1234},
{2,1238},
{11,1245}
};
for (auto test : testCases){
auto f2bound = std::bind(f2, a1, std::placeholders::_2);
runTest (test, f2bound);
}
}
But the compiler says 'no' :
~/src/cpplay/onestens$ g++ -m64 --std=c++11 -o soq.out soQuestionBind.cpp -g
soQuestionBind.cpp: In function ‘void testf2()’:
soQuestionBind.cpp:50:31: error: no matching function for call to ‘runTest(std::pair<long int, long int>&, std::_Bind<long int (*(long int, std::_Placeholder<2>))(long int, long int)>&)’
runTest (test, f2bound);
^
soQuestionBind.cpp:7:6: note: candidate: template<class In, class Exp> void runTest(std::pair<_T1, _T2>, Exp (*)(In))
void runTest (
^
soQuestionBind.cpp:7:6: note: template argument deduction/substitution failed:
soQuestionBind.cpp:50:31: note: mismatched types ‘Exp (*)(In)’ and ‘std::_Bind<long int (*(long int, std::_Placeholder<2>))(long int, long int)>’
runTest (test, f2bound);
^
I'm a bit behind C++11 (and 14 and 17) but this should be possible, right?
I guess the object returned by std::bind couldn't be coerced into a simple function pointer... so how must my template parameter be defined to accept the bound function?

I guess the object returned by std::bind couldn't be coerced into a simple function pointer.
Correct.
The typical way of getting generic callables is to use a simple template parameter. No need to use function pointers, std::function or whatever:
template <typename T, typename U, typename F>
void runTest (
std::pair<T, U> testParams,
F testFunction )
{
auto result = testFunction(testParams.first);
// do something ...
}
Now you can use std::bind, but I'd recommend to use a lambda instead.

Related

Failure to deduce template argument std::function from lambda function

While exploring templates in C++, I stumbled upon the example in the following code:
#include <iostream>
#include <functional>
template <typename T>
void call(std::function<void(T)> f, T v)
{
f(v);
}
int main(int argc, char const *argv[])
{
auto foo = [](int i) {
std::cout << i << std::endl;
};
call(foo, 1);
return 0;
}
To compile this program, I am using the GNU C++ Compiler g++:
$ g++ --version // g++ (Ubuntu 6.5.0-1ubuntu1~16.04) 6.5.0 20181026
After compiling for C++11, I get the following error:
$ g++ -std=c++11 template_example_1.cpp -Wall
template_example_1.cpp: In function ‘int main(int, const char**)’:
template_example_1.cpp:15:16: error: no matching function for call to ‘call(main(int, const char**)::<lambda(int)>&, int)’
call(foo, 1);
^
template_example_1.cpp:5:6: note: candidate: template<class T> void call(std::function<void(T)>, T)
void call(std::function<void(T)> f, T v)
^~~~
template_example_1.cpp:5:6: note: template argument deduction/substitution failed:
template_example_1.cpp:15:16: note: ‘main(int, const char**)::<lambda(int)>’ is not derived from ‘std::function<void(T)>’
call(foo, 1);
^
(same for C++14 and C++17)
From the compiler error and notes I understand that the compiler failed to deduce the type of the lambda, since it cannot be matched against std::function.
Looking at previous questions (1, 2, 3, and 4) regarding this error, I am still confused about it.
As pointed out in answers from questions 3 and 4, this error can be fixed by explicitly specifying the template argument, like so:
int main(int argc, char const *argv[])
{
...
call<int>(foo, 1); // <-- specify template argument type
// call<double>(foo, 1) // <-- works! Why?
return 0;
}
However, when I use other types instead of int, like double, float, char, or bool, it works as well, which got me more confused.
So, my questions are as follow:
Why does it work when I explicitly specify int (and others) as the template argument?
Is there a more general way to solve this?
A std::function is not a lambda, and a lambda is not a std::function.
A lambda is an anonymous type with an operator() and some other minor utility. Your:
auto foo = [](int i) {
std::cout << i << std::endl;
};
is shorthand for
struct __anonymous__type__you__cannot__name__ {
void operator()(int i) {
std::cout << i << std::endl;
}
};
__anonymous__type__you__cannot__name__ foo;
very roughly (there are actual convert-to-function pointer and some other noise I won't cover).
But, note that it does not inherit from std::function<void(int)>.
A lambda won't deduce the template parameters of a std::function because they are unrelated types. Template type deduction is exact pattern matching against types of arguments passed and their base classes. It does not attempt to use conversion of any kind.
A std::function<R(Args...)> is a type that can store anything copyable that can be invoked with values compatible with Args... and returns something compatible with R.
So std::function<void(char)> can store anything that can be invoked with a char. As int functions can be invoked with a char, that works.
Try it:
void some_func( int x ) {
std::cout << x << "\n";
}
int main() {
some_func('a');
some_func(3.14);
}
std::function does that some conversion from its signature to the callable stored within it.
The simplest solution is:
template <class F, class T>
void call(F f, T v) {
f(v);
}
now, in extremely rare cases, you actually need the signature. You can do this in c++17:
template<class T>
void call(std::function<void(T)> f, T v) {
f(v);
}
template<class F, class T>
void call(F f_in, T v) {
std::function f = std::forward<F>(f_in);
call(std::move(f), std::forward<T>(v));
}
Finally, your call is a crippled version of std::invoke from c++17. Consider using it; if not, use backported versions.

Generic Exponential Backoff Retry Mechanism C++11

I have written a generic exponential backoff retry loop in C++11. I'm using std::function to pass the callable to retry loop. callable will be retried if isRetriable function returns true.
#include <algorithm>
#include <cassert>
#include <chrono>
#include <functional>
#include <iostream>
#include <thread>
constexpr int64_t max_backoff_milliseconds = 30000; // 30 seconds
template <class R, class... Args>
R Retry(int max_retry_count, int64_t initial_dealy_milliseconds,
const std::function<bool(R)> &isRetriable,
const std::function<R(Args...)> &callable, Args &&... args)
{
int retry_count = 0;
while (true) {
auto status = callable(std::forward<Args>(args)...);
if (!IsRetriable(status)) {
return status;
}
if (retry_count >= max_retry_count) {
// Return status and abort retry
return status;
}
int64_t delay_milliseconds = 0;
if (initial_dealy_milliseconds > 0) {
delay_milliseconds =
std::min(initial_dealy_milliseconds << retry_count,
max_backoff_milliseconds);
}
std::cout << "Callable execution failed. Retry Count:"
<< retry_count + 1 << std::endl;
std::this_thread::sleep_for(
std::chrono::milliseconds(delay_milliseconds));
retry_count++;
}
}
bool isRetriable(int status) {
if (status == 5)
return true;
return false;
}
int foo(int x, int y) {
static int a = 1;
a += (x + y);
return a / 6;
}
int main() {
auto result = Retry(1000, 100, isRetriable, foo, 1, 3);
std::cout << result << std::endl;
return 0;
}
When I compile it, I'm getting below error:
prog.cpp: In function ‘int main()’:
prog.cpp:50:71: error: no matching function for call to ‘Retry(int,
int, bool (&)(int), int (&)(int, int), int, int)’
auto result = Retry<int, int, int>(1000, 100, isRetriable, foo, 1, 3);
^
prog.cpp:11:3: note: candidate: template<class R, class ... Args> R
Retry(int, int64_t, const std::function<bool(R)>&, const
std::function<_Res(_ArgTypes ...)>&, Args&& ...)
R Retry(int max_retry_count,
^~~~~
prog.cpp:11:3: note: template argument deduction/substitution failed:
prog.cpp:50:71: note: mismatched types ‘const
std::function<int(_ArgTypes ...)>’ and ‘int(int, int)’
auto result = Retry<int, int, int>(1000, 100, isRetriable, foo, 1, 3);
^
Could someone explain to me why I have this error?
I'm sure there's a good duplicate for this but...
Here's a shorter reproduction:
template <typename T> void foo(std::function<bool(T)> ) { }
bool maybe(int ) { return false; }
foo(maybe); // error: no matching function call to 'foo(bool (&)(int))'
You may ask - what?! maybe is something that's callable with some T that returns bool. But that's not how template deduction works. In order to deduce std::function<bool(T)> against an argument, that argument needs to be a std::function. maybe isn't a std::function, it's just a function, so that deduction fails. Any kind of deduction with a different kind of expression will also fail:
foo([](int ) { return true; }); // also error
Basically, trying to deduce a std::function is almost always the wrong thing to do. First, it's wrong because it won't work. Second, it's wrong because even if it did work, you're incurring type erasure in a context in which you probably don't need it.
What you want to do instead is deduce arbitrary callables, and then determine what these other arguments are based on those callables. The return type of callable is just what you get when you call callable with Args..., and you want to ensure that isRetriable is a predicate on that type.
One approach to that is:
template <typename Predicate, typename Callable, typename... Args,
// figure out what the callable returns
typename R = std::decay_t<std::invoke_result_t<Callable&, Args...>>,
// require that Predicate is actually a Predicate
std::enable_if_t<
std::is_convertible_v<std::invoke_result_t<Predicate&, R>, bool>,
int> = 0>
R Retry(int max_retry_count, int64_t initial_dealy_milliseconds,
Predicate&& isRetriable,
Callable&& callable,
Args&&... args)
{
// ....
}

Template Parameter Pack Fails on Clang but not VS 2015

I'm working on a function which invokes a supplied function with a variable number of arguments. It compiles and works correctly on Visual Studio 2015, but fails to compile on Clang . I've prepared a demonstration which shows what I'm trying to do. The error I get in Clang is:
prog.cpp: In function 'int main()': prog.cpp:31:2: error: no matching
function for call to 'run(std::vector&, void ()(int&, const
int&), const int&)' ); ^ prog.cpp:7:6: note: candidate:
template void
run(std::vector&, const std::function&,
mutrArgs ...) void run(
^ prog.cpp:7:6: note: template argument deduction/substitution failed: prog.cpp:31:2: note: mismatched types 'const
std::function' and 'void ()(int&, const
int&)' );
#include <functional>
#include <iostream>
#include <vector>
using namespace std;
template<int RepeatTimes, class ... mutrArgs>
void run(
vector<int>& vec,
const function<void(int&, mutrArgs ...)>& mutr,
mutrArgs ... args
)
{
for (int times{0} ; times < RepeatTimes ; ++times)
for (auto& item : vec)
mutr(item, args...);
}
void adder(int& i, const int& val)
{
i += val;
}
int main()
{
vector<int> v{0,1,2,3,4,5,6,7,8,9};
const int addValue{4};
run<2, const int&>(
v,
&adder,
addValue
);
for (auto i : v)
cout << i << " ";
cout << endl;
return 0;
}
run<2, const int&> just state the first argument, but doesn't deactivate deduction.
run<2, const int&>(v, &adder, addValue);
has 2 places to deduce mutrArgs:
addValue -> mutrArgs = { const int& }
&adder which is not a std::function and so fail.
Taking address of function fix that problem
auto call_run = &run<2, const int&>;
call_run(v, &adder, addValue);
Strangely, clang doesn't support the inlined usage contrary to gcc :/
(&run<2, const int&>)(v, &adder, addValue);
If you want to disable deduction, you may make your template arg non deducible:
template <typename T> struct identity { using type = T; };
template <typename T> using non_deducible_t = typename identity<T>::type;
And then
template<int RepeatTimes, class ... mutrArgs>
void run(
std::vector<int>& vec,
const std::function<void(int&, non_deducible_t<mutrArgs> ...)>& mutr,
non_deducible_t<mutrArgs> ... args
)
Demo
Even if in your case a simple typename F as suggested by Joachim Pileborg seems better.
If you look at all standard library algorithm function, at least the ones taking a "predicate" (a callable object) they take that argument as a templated type.
If you do the same it will build:
template<int RepeatTimes, typename F, class ... mutrArgs>
void run(
vector<int>& vec,
F mutr,
mutrArgs ... args
)
{
...
}
See here for an example of you code. Note that you don't need to provide all template arguments, the compiler is able to deduce them.

Template substitution failure with std::function

I am trying to pass a callback function as function parameter. But getting template substitution failure errors in following code. Not sure why template substitution is failing.
#include<iostream>
#include <map>
#include <tuple>
#include <functional>
template<typename A,typename B>
void myfun(std::map<A,B> & mm, std::function<std::tuple<A,B>(void)> fn)
{
A key;
B val;
std::tie(key,val) = fn();
mm[key] = val;
}
std::tuple<std::string,int> fun()
{
return std::make_tuple(std::string("hi"),1);
}
int main()
{
std::map<std::string,int> gg;
#if 0
//fixed version
std::function<std::tuple<std::string,int>(void)> yy = fun;//fixed
myfun(gg,yy);//fixed
#else
// error causing code
myfun(gg,fun);
#endif
}
And error is as following
main.cpp:8:6: note: template argument deduction/substitution failed:
main.cpp:25:17: note: mismatched types 'std::function<std::tuple<_T1, _T2>()>' and 'std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> (*)()'
myfun(gg,fun);
The compiler can't both cast to a std::function and deduce the template arguments. It doesn't understand the mapping between an arbitrary function pointer and a std::function.
There are a few ways round this.
You could explicitly create a std::function at the call site:
myfun(gg,std::function<std::tuple<std::string,int>(void)>{fun});`
You could write a make_function function to deduce the types for you. You can find discussions and implementations of this online, such as here, here and here.
myfun(gg,make_function(fun));
You could just forget about std::function and deduce the entire function type. This is the approach I would take:
template<typename A,typename B, typename Fun>
void myfun(std::map<A,B> & mm, Fun fn)
{
A key;
B val;
std::tie(key,val) = fn();
mm[key] = val;
}

g++ compiler error: couldn't deduce template parameter ‘_Funct’

I'm trying to use an ANSI C++ for_each statement to iterate over and print the elements of a standard vector. It works if I have the for_each call a non-overloaded function, but yields a compiler error if I have it call an overloaded function.
Here's a minimal test program to show where the compiler error occurs:
#include <algorithm>
#include <iostream>
#include <vector>
struct S {
char c;
int i;
};
std::vector<S> v;
void print_struct(int idx);
void print_struct(const struct S& s);
// f: a non-overloaded version of the preceding function.
void f(const struct S& s);
int main()
{
v.push_back((struct S){'a', 1});
v.push_back((struct S){'b', 2});
v.push_back((struct S){'c', 3});
for (unsigned int i = 0; i < v.size(); ++i)
print_struct(i);
/* ERROR! */
std::for_each(v.begin(), v.end(), print_struct);
/* WORKAROUND: */
std::for_each(v.begin(), v.end(), f);
return 0;
}
// print_struct: Print a struct by its index in vector v.
void print_struct(int idx)
{
std::cout << v[idx].c << ',' << v[idx].i << '\n';
}
// print_struct: Print a struct by reference.
void print_struct(const struct S& s)
{
std::cout << s.c << ',' << s.i << '\n';
}
// f: a non-overloaded version of the preceding function.
void f(const struct S& s)
{
std::cout << s.c << ',' << s.i << '\n';
}
I compiled this in openSUSE 12.2 using:
g++-4.7 -ansi -Wall for_each.cpp -o for_each
The full error message is:
for_each.cpp: In function ‘int main()’:
for_each.cpp:31:48: error: no matching function for call to ‘for_each(std::vector<S>::iterator, std::vector<S>::iterator, <unresolved overloaded function type>)’
for_each.cpp:31:48: note: candidate is:
In file included from /usr/include/c++/4.7/algorithm:63:0,
from for_each.cpp:5:
/usr/include/c++/4.7/bits/stl_algo.h:4436:5: note: template<class _IIter, class _Funct> _Funct std::for_each(_IIter, _IIter, _Funct)
/usr/include/c++/4.7/bits/stl_algo.h:4436:5: note: template argument deduction/substitution failed:
for_each.cpp:31:48: note: couldn't deduce template parameter ‘_Funct’
I don't see any search results for this particular error on Stack Overflow, or on the web generally. Any help would be appreciated.
A names refers to an overload set. You'll need to specify which overload you want:
std::for_each(v.begin(), v.end(), (void (&)(S const&)) print_struct);
Another approach is to use a polymorphic callable function object as a helper:
struct PrintStruct
{
template <typename T> void operator()(T const& v) const
{ return print_struct(v); }
};
int main()
{
PrintStruct helper;
std::vector<S> sv;
std::vector<int> iv;
// helper works for both:
std::for_each(sv.begin(), sv.end(), helper);
std::for_each(iv.begin(), iv.end(), helper);
std::for_each declaration looks like this:
template<class InputIter, class Func>
void for_each(InputIter first, InputIter last, Func func);
As you can see, it takes anything you give it as the third parameter. There is no restriction that it has to be a callable type of a certain signature or a callable type at all.
When dealing with overloaded functions, they're inherently ambiguous unless you give them some context to select the right one. In a call to an overloaded function, this context are the arguments you pass. When you need a pointer, however, you can't use arguments as a context, and the for_each parameter also doesn't count as a context, since it takes anything.
As an example of where a function parameter can be a valid context to select the right overload, see this:
// our overloads
void f(int){}
void f(double){}
typedef void (*funcptr_type)(int);
void g(funcptr_type){}
// ...
g(&f); // will select 'void f(int)' overload, since that's
// the only valid one given 'g's parameter
As you can see, you give a clear context here that helps the compiler select the right overload and not have it ambiguous. std::for_each's parameters do not give such a context, since they take anything.
There are two solutions:
manually provide the context either by
casting to the right function pointer type, or
using an intermediate variable of the right type and passing that
use a non-overloaded function that dispatches to an overloaded one (as you did with f)
Note that in C++11, you could also use a lambda for the second option:
std::for_each(v.begin(), v.end(), [](const S& s){ print_struct(s); });
Some notes on your code:
(struct S){'a', 1} is a compound literal and not standard C++
you don't need struct S in C++, only S suffices