Reputation: 853
I'm writing a function that takes a functor as an argument. The arguments of the functor's call operator are templated. A very simplified version of what I'm trying to do is:
#include <iostream>
#include <functional>
#include <array>
template <const size_t N>
using CVec = std::array<double,N>;
template<const size_t N>
using ode_fun = std::function<CVec<N>(const CVec<N>&)>;
template<const size_t N>
void step( const CVec<N>& x, ode_fun<N> sys)
{
sys(x);
}
struct foo_t
{
CVec<2> operator()( const CVec<2>& x_in)
{
CVec<2> xdot;
std::cout << "x_in: [" << x_in[0] << ", " << x_in[1] << "]\n";
return xdot;
}
CVec<2> x;
};
int main()
{
foo_t foo;
foo.x[0] = -.5;
foo.x[1] = 1.0f;
CVec<2> x;
x[0] = 12.0;
x[1] = 23.2;
step(x, foo);
}
however when compiling, I get this error:
temp_arg_subs_fail.cpp: In function ‘int main()’:
temp_arg_subs_fail.cpp:42:14: error: no matching function for call to ‘step(CVec<2>&, foo_t&)’
step(x, foo);
^
temp_arg_subs_fail.cpp:12:6: note: candidate: template<long unsigned int N> void step(CVec<N>&, ode_fun<N>)
void step( const CVec<N>& x, ode_fun<N> sys)
^~~~
temp_arg_subs_fail.cpp:12:6: note: template argument deduction/substitution failed:
temp_arg_subs_fail.cpp:42:14: note: ‘foo_t’ is not derived from ‘std::function<std::array<double, N>(const std::array<double, N>&)>’
step(x, foo);
^
However this works:
#include <functional>
#include <iostream>
using my_fn = std::function<int(int, int)>;
void summer(int x, int y, my_fn fn)
{
std::cout << "summer: " << fn(x,y) << std::endl;
}
struct foo_t
{
int operator()(int x, int y)
{
return x + y + z;
}
int z = 0;
};
int main ()
{
foo_t foo;
foo.z = 5;
summer(3,4,foo);
return 0;
}
Substantially, the only difference I can tell between the two is that one is templated and the other isn't. Is it because the step function in the first snippet is only a template and not instantiated or something else?
Upvotes: 1
Views: 65
Reputation: 66190
The problem is that step()
require an ode_fun<N>
object as second argument (that is a std::function<std::array<double, N>(std::array<double, N> const &)>
) and N
is to be deduced.
But if you pass foo
, that is a foo_t
object that can be converted to a ode_fun<2>
but (this is the point) isn't a ode_fun<2>
object, the compiler can't deduce the N
value.
You can solve the problem in two obvious ways.
(1) pass a ode_fun<2>
object to step()
ode_fun<2> foo2 { foo };
step(x, foo2);
(2) or deduce a simple type F
(as "functional") in step()
, so all functional are deducible
template<const size_t N, typename F>
void step( const CVec<N>& x, F sys)
{
sys(x);
}
Is it because the step function in the first snippet is only a template and not instantiated or something else?
Exactly.
In your not-template example, summer()
receive a std::function<int(int, int)>
.
Nothing is to be deduced so, passing it a foo_t
object that isn't a std::function<int(int, int)>
but can be converted to it, the compiler convert foo
to std::function<int(int, int)>
.
Upvotes: 1