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.
Related
I have this MCVE:
#include <stdio.h>
#include <atomic>
template<typename T> void assertVariableHasBeenSet( T, const char * );
template<> void assertVariableHasBeenSet<std::atomic<double> &>
( std::atomic<double> & myDouble,
const char * variableName
)
{
printf( "Double:%s=%f\n", variableName, myDouble.load() );
};
int main()
{
std::atomic<double> myDoubleAtomic {23.45};
assertVariableHasBeenSet( myDoubleAtomic, "myDoubleAtomic" );
}
I get this compiler error:
getType.cpp: In function ‘int main()’:
getType.cpp:14:61: error: use of deleted function ‘std::atomic<_Tp>::atomic(const std::atomic<_Tp>&) [with _Tp = double]’
assertVariableHasBeenSet( myDoubleAtomic, "myDoubleAtomic" );
^
In file included from getType.cpp:2:0:
/usr/local/include/c++/4.9.4/atomic:169:7: note: declared here
atomic(const atomic&) = delete;
^
getType.cpp:4:27: error: initializing argument 1 of ‘void assertVariableHasBeenSet(T, const char*) [with T = std::atomic<double>]’
How can I pass a std::atomic<double> reference to the specialized template?
In a normal function it is possible.
For this case, T will be deduced as std::atomic<double>, not std::atomic<double> &. Then the primary template will always be invoked instead of the specialization.
You can specify the template argument explicitly, e.g.
assertVariableHasBeenSet<std::atomic<double> &>(myDoubleAtomic, "myDoubleAtomic");
Or apply overloading.
template<typename T> void assertVariableHasBeenSet( T, const char * );
void assertVariableHasBeenSet( std::atomic<double> & myDouble,
const char * variableName
)
{
printf( "Double:%s=%f\n", variableName, myDouble.load() );
}
Your issue is here:
template<typename T> void assertVariableHasBeenSet( T, const char * );
The primary template will be chosen because myDoubleAtomic is of type std::atomic<double>, not std::atomic<double> &.
The primary template tries to pass T by value, requiring a copy. std::atomic has a deleted copy constructor resulting in that error.
You should tell the compiler what type to use explicitly :
assertVariableHasBeenSet<std::atomic<double> &>(myDoubleAtomic, "myDoubleAtomic" );
The first thing to happen is overload resolution. During overload resolution the type T is deduced as std::atomic<double>. Next the proper specialisation is determined. There is no specialised version and the primary template is used. The specialisation for std::atomic<double>& will never be found by deduction.
There are two approaches to fix the problem (I don’t consider specifying the type explicitly a solution):
Declare the primary template to take a forwarding reference T&& as this would deduce T as std::atomic<double>&.
Instead of template specialisation use overloading, i.e., remove the template<> and the <std::atomic<double>&> after the function name.
Consider the following code:
#include <iostream>
#include <functional>
int main() {
auto run = [](auto&& f, auto&& arg) {
f(std::forward<decltype(arg)>(arg));
};
auto foo = [](int &x) {};
int var;
auto run_foo = std::bind(run, foo, var);
run_foo();
return 0;
}
Which gives the following compilation error when compiled with clang:
$ clang++ -std=c++14 my_test.cpp
my_test.cpp:6:9: error: no matching function for call to object of type 'const (lambda at my_test.cpp:8:16)'
f(std::forward<decltype(arg)>(arg));
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1/../../../../include/c++/6.3.1/functional:998:14: note: in instantiation of function template specialization 'main()::(anonymous class)::operator()<const (lambda at my_test.cpp:8:16) &, const int &>' requested here
= decltype( std::declval<typename enable_if<(sizeof...(_Args) >= 0),
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1/../../../../include/c++/6.3.1/functional:1003:2: note: in instantiation of default argument for 'operator()<>' required here
operator()(_Args&&... __args) const
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
my_test.cpp:11:12: note: while substituting deduced template arguments into function template 'operator()' [with _Args = <>, _Result = (no value)]
run_foo();
^
my_test.cpp:8:16: note: candidate function not viable: 1st argument ('const int') would lose const qualifier
auto foo = [](int &x) {};
^
my_test.cpp:8:16: note: conversion candidate of type 'void (*)(int &)'
1 error generated.
Why is arg deduced to be const int& instead of just int&?
std::bind documentation says:
Given an object g obtained from an earlier call to bind, when it is
invoked in a function call expression g(u1, u2, ... uM), an invocation
of the stored object takes place, as if by std::invoke(fd,
std::forward(v1), std::forward(v2), ...,
std::forward(vN)), where fd is a value of type std::decay_t the
values and types of the bound arguments v1, v2, ..., vN are determined
as specified below.
...
Otherwise, the
ordinary stored argument arg is passed to the invokable object as
lvalue argument: the argument vn in the std::invoke call above is
simply arg and the corresponding type Vn is T cv &, where cv is the
same cv-qualification as that of g.
But in this case, run_foo is cv-unqualified. What am I missing?
MWE:
#include <functional>
int main() {
int i;
std::bind([] (auto& x) {x = 1;}, i)();
}
[func.bind]/(10.4) states that the cv-qualifiers of the argument passed to the lambda are those of the argument to bind, augmented by the cv-qualifiers of the call wrapper; but there are none, and thus a non-const int should be passed in.
Both libc++ and libstdc++ fail to resolve the call. For libc++, reported as #32856, libstdc++ as #80564. The main problem is that both libraries infer the return type in the signature somehow, looking like this for libstdc++:
// Call as const
template<typename... _Args, typename _Result
= decltype( std::declval<typename enable_if<(sizeof...(_Args) >= 0),
typename add_const<_Functor>::type&>::type>()(
_Mu<_Bound_args>()( std::declval<const _Bound_args&>(),
std::declval<tuple<_Args...>&>() )... ) )>
_Result operator()(_Args&&... __args) const
During template argument deduction as necessitated by overload resolution, the default template argument will be instantiated, which causes a hard error due to our ill-formed assignment inside the closure.
This can be fixed by perhaps a deduced placeholder: remove _Result and its default argument entirely, and declare the return type as decltype(auto). This way, we also get rid of SFINAE which influences overload resolution and thereby induces incorrect behaviour:
#include <functional>
#include <type_traits>
struct A {
template <typename T>
std::enable_if_t<std::is_const<T>{}> operator()(T&) const;
};
int main() {
int i;
std::bind(A{}, i)();
}
This should not compile—as explained above, the argument passed to A::operator() should be non-const because i and the forwarding call wrapper are. However, again, this compiles under libc++ and libstdc++, because their operator()s fall back on const versions after the non-const ones fail under SFINAE.
Why doesn't the following code compile (in C++11 mode)?
#include <vector>
template<typename From, typename To>
void qux(const std::vector<From>&, To (&)(const From&)) { }
struct T { };
void foo(const std::vector<T>& ts) {
qux(ts, [](const T&) { return 42; });
}
The error message is:
prog.cc:9:5: error: no matching function for call to 'qux'
qux(ts, [](const T&) { return 42; });
^~~
prog.cc:4:6: note: candidate template ignored: could not match 'To (const From &)' against '(lambda at prog.cc:9:13)'
void qux(const std::vector<From>&, To (&)(const From&)) { }
^
But it doesn't explain why it couldn't match the parameter.
If I make qux a non-template function, replacing From with T and To with int, it compiles.
A lambda function isn't a normal function. Each lambda has its own type that is not To (&)(const From&) in any case.
A non capturing lambda can decay to To (*)(const From&) in your case using:
qux(ts, +[](const T&) { return 42; });
As noted in the comments, the best you can do to get it out from a lambda is this:
#include <vector>
template<typename From, typename To>
void qux(const std::vector<From>&, To (&)(const From&)) { }
struct T { };
void foo(const std::vector<T>& ts) {
qux(ts, *+[](const T&) { return 42; });
}
int main() {}
Note: I assumed that deducing return type and types of the arguments is mandatory for the real problem. Otherwise you can easily deduce the whole lambda as a generic callable object and use it directly, no need to decay anything.
If you don't need to use the deduced To type, you can just deduce the type of the whole parameter:
template<typename From, typename F>
void qux(const std::vector<From>&, const F&) { }
Correct me if I am wrong, but template parameters deduction deduces only exact types without considering possible conversions.
As a result the compiler cannot deduce To and From for To (&)(const From&) because qux expects a reference to function, but you provide a lambda which has its own type.
You have left absolutely no chance to compiler to guess what is To. Thus, you need to specify it explicitly.
Also, lambda here needs to be passed by pointer.
Finally, this version compiles ok:
template<typename From, typename To>
void qux(const std::vector<From>&, To (*)(const From&)) { }
struct T { };
void foo(const std::vector<T>& ts) {
qux<T,int>(ts,[](const T&) { return 42; });
}
You're expecting both implicit type conversions (from unnamed function object type to function reference type) and template type deduction to happen. However, you can't have both, as you need to know the target type to find the suitable conversion sequence.
But it doesn't explain why it couldn't match the parameter.
Template deduction tries to match the types exactly. If the types cannot be deduced, deduction fails. Conversions are never considered.
In this expression:
qux(ts, [](const T&) { return 42; });
The type of the lambda expression is some unique, unnamed type. Whatever that type is, it is definitely not To(const From&) - so deduction fails.
If I make qux a non-template function, replacing From with T and To with int, it compiles.
That is not true. However, if the argument was a pointer to function rather than a reference to function, then it would be. This is because a lambda with no capture is implicitly convertible to the equivalent function pointer type. This conversion is allowed outside of the context of deduction.
template <class From, class To>
void func_tmpl(From(*)(To) ) { }
void func_normal(int(*)(int ) ) { }
func_tmpl([](int i){return i; }); // error
func_tmpl(+[](int i){return i; }); // ok, we force the conversion ourselves,
// the type of this expression can be deduced
func_normal([](int i){return i; }); // ok, implicit conversion
This is the same reason why this fails:
template <class T> void foo(std::function<T()> );
foo([]{ return 42; }); // error, this lambda is NOT a function<T()>
But this succeeds:
void bar(std::function<int()> );
bar([]{ return 42; }); // ok, this lambda is convertible to function<int()>
The preferred approach would be to deduce the type of the callable and pick out the result using std::result_of:
template <class From,
class F&&,
class To = std::result_of_t<F&&(From const&)>>
void qux(std::vector<From> const&, F&& );
Now you can pass your lambda, or function, or function object just fine.
include
template <typename R, typename S, typename T>
T const min (R const& a, S const& b)
{
T val;
if( a > b )
{
val = static_cast<T>( b );
}
else
{
val = static_cast<T>( a );
}
return val;
}
// CANNOT change anything above this line --------------------
void B()
{
int val =0;
// Only change the next line
val = min (5,4.2);
assert( val == 4 );
}
when the code is compiled the following error is thrown
error C2783: 'const T min(const R &,const S &)' : could not deduce template argument for 'T'
Stuck trying to solve this.. . any help will be appreciated
The compiler error is telling you that it can't figure out what type T is supposed to be in your call to min, since you haven't specified it and the return type of a function or function template are not used during overload resolution or template argument deduction (unless it's a conversion operator, of course).
Since you can't change the definition of min (which is stupid) your only choice is to explicitly specify T in the call. However, since T is the last template parameter, you have to specify the two preceding template arguments too! Like this:
val = min<int, double, int>(5, 4.2);
The compiler cannot deduce the template argument if you don't use it.
That being said what you would do in this situation is specify in specify the template arguments when you call the function min. Just like this:
void B()
{
int val = 0;
// Only change the next line
val = min<int, double, int>(5, 4.2);
assert(val == 4);
}
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