Function pointer ambiguity with templated parameters - c++

I'm trying to pass an overloaded function pointer to template function as a parameter.
float Function1(float par1)
{
return 0;
}
float Function1(float par1, float par2)
{
return 0;
}
template<typename R, typename A1>
void Bind(R(*func)(A1))
{
std::cout << "Correct one called\n";
}
template<typename R, typename A1, typename A2>
void Bind(R(*func)(A1, A2))
{
std::cout << "False one called\n";
}
int main()
{
Bind<float, float>(&Function1);
}
Even tho i call the function with 2 float parameters explicity, compiler can't seem to resolve the correct call.
Compiler shows an 'ambiguous function call' error.
I have created a small sample here:
http://liveworkspace.org/code/4kVlUY$195
What's the cause of this error?
Thank you.

The ambiguity comes when you try to take Function1's address. The compiler sees 2 overloads and it can't know which one you're referring to. You need to explicitly indicate which one you want:
Bind(
static_cast<float(*)(float, float)>(&Function1)
);
You're indicating template arguments explicitly on the call to Bind, but that's too late, the ambiguity was found before that point.

You need to resolve the ambiguity manually, such as with a cast expression.
Bind<float, float>( static_cast< float (*)(float par1, float par2)>( &Function1 ));
According to the error message, it's not Function1 that's ambiguous, it's Bind.
Compilation finished with errors:
source.cpp:31:4: error: call to 'Bind' is ambiguous
Bind<float, float>(&Function1);
^~~~~~~~~~~~~~~~~~
source.cpp:18:6: note: candidate function [with R = float, A1 = float]
void Bind(R(*func)(A1))
^
source.cpp:24:6: note: candidate function [with R = float, A1 = float, A2 = float]
void Bind(R(*func)(A1, A2))
The problems is that you specified two arguments, <float, float>, but that doesn't exclude the possibility of a third argument which is automatically deduced. C++ allows for explicit and implicit arguments to the same function template call!
Another solution is to force it to resolve the template name without considering implicit arguments. This works too, but it's more hackish:
(*&Bind<float, float>)(&Function1); // Taking address first hides arguments from deduction

Related

"template argument deduction/substitution failed" error with function object with parameter pack

I'm trying to make a function that takes a variable number of parameters of any type, but even the simple example I made is getting an error
#include <iostream>
#include <functional>
template<class... Ts>
void callFunction(const std::function<void(Ts...)>& function, Ts... parameters)
{
function(parameters...);
}
void myFunc(const std::string& output)
{
std::cout << output << std::endl;
}
int main()
{
callFunction<const std::string&>(&myFunc, "Hello world");
return 0;
}
When I run the above code in Ideone, I get this error:
prog.cpp: In function ‘int main()’:
prog.cpp:17:57: error: no matching function for call to ‘callFunction(void (*)(const string&), const char [12])’
callFunction<const std::string&>(&myFunc, "Hello world");
^
prog.cpp:5:6: note: candidate: template<class ... Ts> void callFunction(const std::function<void(Ts ...)>&, Ts ...)
void callFunction(const std::function<void(Ts...)>& function, Ts... parameters)
^~~~~~~~~~~~
prog.cpp:5:6: note: template argument deduction/substitution failed:
prog.cpp:17:57: note: mismatched types ‘const std::function<void(Ts ...)>’ and ‘void (*)(const string&) {aka void (*)(const std::__cxx11::basic_string<char>&)}’
callFunction<const std::string&>(&myFunc, "Hello world");
A simple suggestion: receive the callable as a deduced typename, not as a std::function
I mean (adding also perfect forwarding)
template <typename F, typename ... Ts>
void callFunction(F const & func, Ts && ... pars)
{ func(std::forward<Ts>(pars)...); }
and, obviously, call it without explicating nothing
callFunction(&myFunc, "Hello world");
This as the additional vantage that avoid the conversion of the callable to a std::function.
Anyway, I see two problems in your code:
1) if you receive the functional as a std::function receiving a list ot arguments types (a variadic list in this case, but isn't important for this problem) as a list of argument of the same types, you have to be sure that the types in the two list match exactly.
This isn't your case because the function receive a std::string const & and you pass as argument a the string literal "Hello world" that is a char const [12] that is a different type.
When the types are to be deduced, this cause a compilation error because the compiler can't choose between the two types.
You could solve receiving two list of types
template <typename ... Ts1, typename Ts2>
void callFunction (std::function<void(Ts1...)> const & function,
Ts2 && ... parameters)
{ function(std::forward<Ts2>(parameters)...); }
but now we have the second problem
2) You pass a pointer function (&myFunc) where callFunction() wait for a std::function.
We have a chicken-egg problem because &myFunc can be converted to a std::function but isn't a std::function.
So the compiler can't deduce the Ts... list of types from &myFunc because isn't a std::function and can't convert &myFunc to a std::function because doesn't know the Ts... type list.
I see that you have explicated the first type in the Ts... list, but isn't enough because the Ts... list is a variadic one so the compiler doesn't know that there is only a type in the Ts... list.
A simple solution to this problem is pass the function as a simple deduced F type.
Otherwise, if you have written callFunction() with two templates types lists, you can pass a std::function to the function
std::function<void(std::string const &)> f{&myFunc};
callFunction(f, "Hello world");
but I don't think is a satisfactory solution.

Pass generic function and its parameters to meta-function

First of all, I feel like this must have been asked already somewhere, but all my searches proved fruitless. If this is indeed a duplicate of something somewhere, I apologize in advance.
I am trying to mass-benchmark a bunch of functions from OpenCV and to do so I wanted to write a small meta-function that takes the function to run, its parameters (which vary according to the function passed) and essentially sets up the timing and runs the function in a loop.
Since I'm planning to pass lambdas to the meta-function as well later on (to benchmark composition of functions), I thought of using std::function.
This is the code I came up with after reading the parameter pack description:
template<typename ...Ts>
void run_test(std::string test_name, int num_repeats, std::function<void(Ts...)> f, Ts... fargs)
{
std::cout << std::endl << "Starting " << test_name << std::endl;
start_timing(test_name);
for(int i=0; i<num_repeats; i++)
{
f(fargs...);
}
end_timing(num_repeats);
}
As you see, functionality is down to a minimum. start_timing and end_timing are simple helper functions beyond the scope of this question.
In my main, I call:
// im_in defined and loaded elsewhere
cv::Mat out(im_in.size(), CV_8U);
run_test(
"erode 3x3",
100,
cv::erode,
im_in, out, cv::Mat::ones(3,3,CV_8U)
);
Now, if I try to compile this, I get:
error: no matching function for call to 'run_test(const char [10], const int&, void (&)(cv::InputArray, cv::OutputArray, cv::InputArray, cv::Point, int, int, const Scalar&), cv::Mat&, cv::Mat&, cv::MatExpr)'
);
^
note: candidate: template<class ... Ts> void run_test(std::__cxx11::string, int, std::function<void(Ts ...)>, Ts ...)
void run_test(std::string test_name, int num_repeats, std::function<void(Ts...)> f, Ts... fargs)
^~~~~~~~
note: template argument deduction/substitution failed:
note: mismatched types 'std::function<void(Ts ...)>' and 'void (*)(cv::InputArray, cv::OutputArray, cv::InputArray, cv::Point, int, int, const Scalar&) {aka void (*)(const cv::_InputArray&, const cv::_OutputArray&, const cv::_InputArray&, cv::Point_<int>, int, int, const cv::Scalar_<double>&)}'
);
So... what am I doing wrong? Why is it having a type mismatch instead of deducing the types in Ts... from the parameters list as I expected?
Update:
After writing the last question above, I realized it might have problems deducing Ts... for the std::function because the parameter comes before the actual parameter list to expand into Ts.... So, I changed my code as follows (essentialy, I moved the f parameter at the end):
void run_test(std::string test_name, int num_repeats, Ts... fargs, std::function<void(Ts...)> f)
{ ... }
Of course, I also adapted the function call accordingly:
cv::Mat out(im_in.size(), CV_8U);
run_test(
"erode 3x3",
NUM_REPEATS,
im_in, out, cv::Mat::ones(3,3,CV_8U),
cv::erode, // <<<<<<<<<<<<<<<<<<<<<<<
);
Now, if I compile, I get a different error:
error: expected primary-expression before ')' token );
The change in error makes me think the order of the parameters was indeed important. Is, however, this the correct one? If so, what am I doing wrong?
Update2:
Writing the first update, it struck me that probably my assumption that f can take a function and convert it to a std::function was probably wrong. After a quick research, it seems it is.
I tried replacing std::function<void(Ts...)> f with both auto f and auto& f (& compiling with C++14 enabled), but the expected primary-expression error is still there.
For all I could research, I couldn't find a way that allows me to just pass the function relying on the compiler to figure out the types.
I'm thinking of adapting C++17's std::apply function implementation shown here adding my timing loop around the invoke call, but I don't understand that code, so the chance of getting something wrong is high.
You might get rid of std::function (which add overhead BTW), and use generic for f too:
template<typename F, typename ...Ts>
void run_test(std::string test_name, int num_repeats, F f, const Ts&... fargs)
{
std::cout << std::endl << "Starting " << test_name << std::endl;
start_timing(test_name);
for(int i=0; i<num_repeats; i++)
{
f(fargs...);
}
end_timing(num_repeats);
}
I realized it might have problems deducing Ts... for the std::function
As cv::erode is not a std::function, Ts... cannot be deduced from it, but would be from extra parameters.
Your problem is that cv::erode has extra (defaulted) parameters.
so you cannot create the std::function<Ts...> with Ts... deduced from parameters.
To bypass that issue, you might use lambda instead:
run_test(
"erode 3x3",
100,
[&](){ cv::erode(im_in, out, cv::Mat::ones(3,3,CV_8U)); }
);
the error expected primary-expression before ')' is because you left a , after your last parameter
parameter pack must always be the last parameters of a functions
you should probably try this
template<typename Callable, typename ...Ts>
void run_test(std::string test_name, int num_repeats, Callable func, Ts&& ... fargs)
{
std::cout << std::endl << "Starting " << test_name << std::endl;
start_timing(test_name);
for(int i=0; i<num_repeats; i++)
{
func(std::forward<Ts>(fargs)...);
}
end_timing(num_repeats);
}

C++ Templates: correct way to return a new type

Sorry for the generic title, but I'm unable to focus the problem.
I have a templatized class method that accept an argument pack and provides a new type in return, to hide the details of the implementation. More specifically, the class handles SQLite queries, and the method calls sqlite3_prepare() to prepare the statement before executing the query.
class Table {
...
template <typename ...Ts>
class PreparedStatement { ... };
template <typename ...Ts>
PreparedStatement<Ts...> prepare(std::tuple<Ts...> tuple) {
// do something
return PreparedStatement<Ts...> ( ... );
}
That works well with "normal" types, but the problem occurs when the arguments are declared const:
const Field<int> fld = createField<int>("name");
...
PreparedStatement<decltype(fld)> s = prepare(make_tuple(fld));
The error is the following:
no match for 'operator =' (operand types are PreparedStatenent<const Field<int>> and PreparedStatement<Field<int>>
I suspect the issue is in my declaration of the function, is there a way to fix this issue and make the function more "elegant" ?
NOTE: I know I can fix the issue by manually declare the s variable, but my doubts are on how the method was implemented.
As Many Asked, here's an example:
#include <tuple>
template <typename T>
struct Field {
};
class Table {
public:
template <typename ...Ts>
class PreparedStatement {
public:
PreparedStatement() {};
};
template <typename ...Ts>
PreparedStatement<Ts...> prepare(std::tuple<Ts...> tuple) {
// do something
return PreparedStatement<Ts...> ( );
}
};
int main()
{
Field<int> fld;
Table t;
Table::PreparedStatement<decltype(fld)> p;
p = t.prepare(std::make_tuple(fld));
// here comes the problem
const Field<int> f2;
Table::PreparedStatement<decltype(f2)> p2;
p2 = t.prepare(std::make_tuple(f2));
return 0;
}
and here's the compiler output
main.cpp: In function 'int main()': main.cpp:35:39: error: no match
for 'operator=' (operand types are 'Table::PreparedStatement >' and 'Table::PreparedStatement >')
p2 = t.prepare(std::make_tuple(f2));
^ main.cpp:10:10: note: candidate: constexpr Table::PreparedStatement >&
Table::PreparedStatement >::operator=(const
Table::PreparedStatement >&)
class PreparedStatement {
^~~~~~~~~~~~~~~~~ main.cpp:10:10: note: no known conversion for argument 1 from 'Table::PreparedStatement >'
to 'const Table::PreparedStatement >&'
main.cpp:10:10: note: candidate: constexpr
Table::PreparedStatement >&
Table::PreparedStatement
::operator=(Table::PreparedStatement >&&) main.cpp:10:10: note: no known conversion for argument 1 from
'Table::PreparedStatement >' to
'Table::PreparedStatement >&&'
UPDATE
As many noted, I could use auto to deduce the type, but in some condition auto cannot practically be used. One is, for example, if I need to declare the statement in the Class Context.
So suppose auto is forbidden for some reason. Isn't any other solution available? See the updated code above.
cppreference.com for make_tuple tells us:
template< class... Types >
tuple<VTypes...> make_tuple( Types&&... args );
For each Ti in Types..., the corresponding type Vi in Vtypes... is
std::decay<Ti>::type unless application of std::decay results in
std::reference_wrapper<X> for some type X, in which case the deduced
type is X&.
While std::decay, among other things, removes cv-qualifiers. So your type will be no PreparedStatement<const Field<int>>, but PreparedStatement<Field<int>>.
You can use auto, as manni66 proposed, to avoid such problems.
auto s = prepare(make_tuple(fld));
I could use auto to deduce the type, but in some condition auto cannot practically be used. One is, for example, if I need to declare the statement in the Class Context. So suppose auto is forbidden for some reason. Isn't any other solution available? See the updated code above.
Instead of auto, you can use a decltype expression that take in count the value returned by prepare.
I mean... instead of
Table::PreparedStatement<decltype(f2)> p2;
you can try with
decltype(t.prepare(std::make_tuple(f2))) p2;
or
decltype(std::declval<Table>().prepare(
std::make_tuple(std::declval<Field<int>>()))) p2;
I suppose you can use a similar decltype() also to declare members of your classes.

Default template argument for function ignored

template < class A, class B, class R = A >
void addMultiplyOperation( std::function< R ( const A&, const B& ) > func )
{
...
}
addMultiplyOperation< float, int >( []( float a, int b ) { return a * b; } );
This gives the compiler error:
In function 'int main(int, char**)':
error: no matching function for call to 'addMultiplyOperation(main(int, char**)::__lambda1)'
addMultiplyOperation< float, int >( []( float a, int b ) { return a * b; } );
^
note: candidate is:
note: template<class A, class B, class R> void addMultiplyOperation(std::function<R(const A&, const B&)>)
void addMultiplyOperation( std::function< R ( const A&, const B& ) > func )
^
note: template argument deduction/substitution failed:
note: 'main(int, char**)::__lambda1' is not derived from 'std::function<R(const float&, const int&)>'
addMultiplyOperation< float, int >( []( float a, int b ) { return a * b; } );
^
Despite having the R template argument default initialised to A, I have to provide the third argument in order for this to compile. Is there something else I have to do in order to use default template arguments?
I'm using g++ v4.8.1.
Despite having the R template argument default initialised to A, I have to provide the third argument in order for this to compile.
Actually, this has nothing to do with the fact that it's a default argument. The compiler can't deduce A and B either. Take a look at this simple example:
template<class A>
void f(function<void(A)> f) { }
int main() {
auto lambda = [](){};
f(lambda);
}
You'd think this would be super easy, and A should be deduced as void. But nope, it can't be done. When deducing template parameters, the compiler doesn't consider what constructors the parameter type would have for each possible combination of template parameters. It would be intractable to perform this sort of deduction in general.
For now, you'll just have to make addMultiplyOperation accept any type, and hope it's callable...
template<class Function>
void addMultiplyOperation(Function func) {
// ....
}
If necessary, there are ways to deduce the types of the arguments that the function object can accept, for example as described in this answer: Is it possible to figure out the parameter type and return type of a lambda?
This will lead to some nasty compilation errors if the object passed in is not actually callable, or takes the wrong number of arguments. For now I'm not sure whether there's a nice way to solve this. Concepts, coming in C++14, should alleviate some of these issues.

c++: why am I getting an error when giving all type parameters of a template function, but OK when omitting a parameter?

In the following template function with a parameter pack and a ReturnType, why is the compiler OK if I omit the last parameter ReturnType, whereas giving me an error (about ambiguity) if I explicitly give the the last type parameter.
Thanks.
#include <functional>
using namespace std;
template<typename... Args, typename ReturnType>
auto make_function(ReturnType(*p)(Args...))
-> std::function<ReturnType(Args...)> {
return {p};
}
int foo1(int x, int y, int z) { return x + y + z;}
float foo1(int x, int y, float z) { return x + y + z;}
int main() {
auto f0 = make_function<int,int,int>(foo1); //OK
//auto f1 = make_function<int,int,int,int>(foo1); //not OK
// test33.cpp:15:48: error: no matching function for call to
// 'make_function(<unresolved overloaded function type>)'
return 0;
}
Credit to Xeo.
Putting a parameter after a parameter pack is a special case where deduction is forced. You cannot explicitly supply an argument to ReturnType. Therefore it goes looking for foo1( int, int, int, int ) and finds nothing.
By the way, if you want to defeat deduction, one trick is to hide the argument list by taking the address of the function: (&make_function<int,int,int,int>)(foo1). This causes Clang to complain specifically
candidate template ignored: couldn't infer template argument 'ReturnType'
and it ICEs GCC (but still prints a diagnostic pointing to the right line).