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;
}
Related
I'm trying to pass a list of pairs of types constructed from boost::mp11::mp_product to a function that takes the pairs along with an additional function argument via boost::mp11::mp_for_each.
The docs I've found for mp_for_each are limited to use with generic lambdas or pure functions, so I can't seem to figure out if the use of std::bind is the way to go; and if it is, what I'm doing wrong yielding the following compiler error:
error: no matching function for call to 'bind'
std::bind(inject_foo, m, std::placeholders::_1));
^~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:2953:1: note: candidate template ignored: couldn't infer template argument '_Fp'
bind(_Fp&& __f, _BoundArgs&&... __bound_args)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/functional:2962:1: note: candidate template ignored: couldn't infer template argument '_Rp'
bind(_Fp&& __f, _BoundArgs&&... __bound_args)
Code I'm using:
#include <pybind11/numpy.h>
#include <boost/mp11.hpp>
#include <functional>
using boost::mp11::mp_product;
using boost::mp11::mp_for_each;
template <typename...> struct type_list {};
// all possible types
using my_type_list = type_list<
double, float, py::ssize_t, int, unsigned int, unsigned long>;
// construct all possible pairs of types with help from boost::mp11
using my_type_pairs = mp_product<
type_list, my_type_list, my_type_list>;
// the C++ function that we bind to a python module in the next function.
template <typename Tx, typename Ty>
py::array<py::ssize_t> foo(p::array_t<Tx> x, py::array_t<Ty>) {
py::array_t<py::ssize_t> z;
// do something with x and y
return z;
}
// bind foo<Tx, Ty> function to py::module m
template <typename Tx, typename Ty>
void inject_foo(py::module_& m, const type_list<Tx, Ty>&) {
m.def("_foo", &foo<Tx, Ty>, py::arg("x").noconvert(), py::arg("y").noconvert());
}
PYBIND11_MODULE(_backend, m) {
// these function calls work as expected:
// inject_foo(m, type_list<double, double>{});
// inject_foo(m, type_list<double, float>{});
// inject_foo(m, type_list<double, int>{});
// .....
// trying to make my life easier with the loop
// over all possible types of pairs is not working
mp_for_each(pg_type_pairs{}, std::bind(inject_foo, m, std::placeholders::_1));
}
PiotrNycz's comment led to an answer:
mp_for_each<pg_type_pairs>([&](const auto& x) { inject_foo(m, x); });
Provides the desired behavior (In the question I was even using the mp_for_each API incorrectly; switching to a lambda helped find that error).
basically I want to integrate a multi-dimensional integral with this recursion.
But the problem itself is a general one. It's not specific for integration.
#include "math.h"
#include <iostream>
#include <functional>
double f(double x,double y,double z){
return x+y+z+1;
}
//Base
double redDim(std::function<double(double)> &f){
return f(0); //a silly integrator for testing
}
// Recursion
template<typename Tfirst=double, typename... Trest>
auto redDim(std::function<double(Tfirst first,Trest... rest)> &f){
return redDim([=](Trest... R){return redDim([=](double x){return f(x,R...);});});
}
int main(){
std::cout<<redDim(f)<<std::endl;
return 0;
}
The problem is, compiler says:
c:\C++\templateTutorial\templateTut.cpp: In function 'int main()':
c:\C++\templateTutorial\templateTut.cpp:24:19: error: no matching function for call to 'redDim(double (&)(double, double, double))'
cout<<redDim(f)<<endl;
^
c:\C++\templateTutorial\templateTut.cpp:12:8: note: candidate: 'double redDim(std::function<double(double)>&)'
double redDim(std::function<double(double)> &f){
^~~~~~
c:\C++\templateTutorial\templateTut.cpp:12:8: note: no known conversion for argument 1 from 'double(double, double, double)' to 'std::function<double(double)>&'
c:\C++\templateTutorial\templateTut.cpp:17:6: note: candidate: 'template<class Tfirst, class ... Trest> auto redDim(std::function<double(Tfirst, Trest ...)>&)'
auto redDim(std::function<double(Tfirst first,Trest... rest)> &f){
^~~~~~
c:\C++\templateTutorial\templateTut.cpp:17:6: note: template argument deduction/substitution failed:
c:\C++\templateTutorial\templateTut.cpp:24:19: note: mismatched types 'std::function<double(Tfirst, Trest ...)>' and 'double(double, double, double)'
cout<<redDim(f)<<endl;
^
The terminal process terminated with exit code: 1
So why is the type of f not matching the requirements of redDim() ?
Thus I can't even test, if my method works.
I hope you could help me!
A function pointer is not a std::function.
Template argument deduction does not do any type conversions, other than a few to-base cases.
Add a redim( double(*f)(Args...) ) template that calls the std function one.
template<class...Args>
auto redDim( double(*f)(Args...) {
return redDim( std::function<double(Args...)>{ f } );
}
and it should work.
This can deduce the signature of the function pointer. It then explicitly converts to a std::function, which then matches your other redim functions.
You do have to explicitly convert your other lambdas to std::functions:
// Recursion
template<typename Tfirst, typename... Trest>
auto redDim(std::function<double(Tfirst first,Trest... rest)> f){
return redDim(
std::function<double(Trest...)>{
[=](Trest... R){
return redDim(
std::function<double(double)>{
[=](double x){return f(x,R...);}
}
);
}
}
);
}
Live example.
Also change the argument for the last redDim to std::function<double(double)> (not a reference). Alternatively, a const&.
Based on Yakk - Adam Nevraumont's answer, the following code should compile:
#include "math.h"
#include <iostream>
#include <functional>
double f(double x,double y,double z){
return x+y+z+1;
}
//Base
double redDim(const std::function<double(double)> &f){
return f(0); //a silly integrator for testing
}
// Recursion
template<typename Tfirst=double, typename... Trest>
auto redDim(const std::function<double(Tfirst first,Trest... rest)> &f) {
return redDim(
std::function<double(Trest...)>{
[=](Trest... R)->double{return redDim([=](double x){return f(x,R...);});}});
}
template<class...Args>
auto redDim( double(*f)(Args...)) {
return redDim( std::function<double(Args...)>{ f } );
}
int main(){
std::cout<<redDim(f)<<std::endl;
return 0;
}
As Yakk already pointed out, std::function and a function pointer don't have the same type. Please note that I've also changed the argument type of redDim to const std::function<...> &). You could also pass rvalue references using the && syntax.
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.
Is this a legitimate method for making sure implicit type conversion does not happen?
#include <string>
#include <iostream>
void func(std::string s)
{
std::cout << "Thanks for the string\n";
}
template<class T>
void func(T)=delete;
int main()
{
func("test1");
// str.cc: In function ‘int main()’:
// str.cc:13:16: error: use of deleted function ‘void func(T) [with T = const char*]’
// func("test1");
// ^
// str.cc:9:6: error: declared here
// void func(T)=delete;
// ^
//
func(std::string("test2"));
return 0;
}
Looks good to me.
It does the same thing to answers.
Yes, that method ensures that implicit conversions are disallowed. However, it also means that this property does not arise from the definition of of void func(string) alone. So, in order to clarify this to readers, you could make it more self-contained as follows:
template <typename T, typename U> using RequireExplicit = enable_if_t<is_same<T, U>>;
template <typename T, typename = RequireExplicit<T, string>>
void func(T){}
I have a compile error when using std::function in a templated member function, the following code is a simple example:
#include <functional>
#include <memory>
using std::function;
using std::bind;
using std::shared_ptr;
class Test {
public:
template <typename T>
void setCallback(function<void (T, int)> cb);
};
template <typename T>
void Test::setCallback(function<void (T, int)> cb)
{
// do nothing
}
class TestA {
public:
void testa(int a, int b) { }
};
int main()
{
TestA testA;
Test test;
test.setCallback(bind(&TestA::testa, &testA, std::placeholders::_1, std::placeholders::_2));
return 0;
}
And come with the following compile error:
testtemplate.cpp: In function ‘int main()’:
testtemplate.cpp:29:92: error: no matching function for call to
‘Test::setCallback(std::_Bind_helper)(int, int),
TestA, const std::_Placeholder<1>&, const
std::_Placeholder<2>&>::type)’
testtemplate.cpp:29:92: note: candidate is: testtemplate.cpp:10:7:
note: template void Test::setCallback(std::function)
testtemplate.cpp:10:7: note: template argument
deduction/substitution failed:
testtemplate.cpp:29:92: note: ‘std::_Bind(TestA*, std::_Placeholder<1>,
std::_Placeholder<2>)>’ is not derived from ‘std::function’
I'm using C++11 and g++ 4.7
To figure out the problem let separate statements:
auto f = bind(&TestA::testa, &testA, _1, _2); // OK
test.setCallback(f); // <<--- Error is here
setCallback needs to know type of T and it can't deduce it from f, so give it a type
test.setCallback<TYPE>(f); // TYPE: int, float, a class, ...
You can make type deduction work with some variant of:
template<typename CALLBACK>
void setCallback(CALLBACK cb) {
typedef CALLBACK::first_argument_type T;
static_assert(is_same_type<CALLBACK,function<void(T,int)>>::value);
...
}
This way CALLBACK can be determined by looking at the argument. It might get into trouble if bind doesn't actually return a std::function but rather something that can be cast as one. I'm not sure.