I'm trying to pass lambda to std::function<> defined via variadic template, but it seems that this doesn't work on gcc.
Is there any reason, why this code doesn't work on gcc 7.4.0 but working correctly on Visual Studio 2017? And is there any way how to make it work also on gcc without the necessity to manually convert it to std::function<> first?
#include <functional>
template<class ...TParams>
int TestFunction(std::function<void(TParams...)> )
{
return 0;
}
void Test()
{
auto fce = [](int /*n*/, double /*d*/) {};
//This doesn't work with error no matching function for call to 'TestFunction<int, double>(Test()::<lambda(int, double)>&)'
TestFunction<int, double>(fce);
//but this works correctly
std::function<void(int, double)> fce2 = fce;
TestFunction<int, double>(fce2);
}
I'm getting following error:
main.cpp: In function 'void Test()':
main.cpp:116:31: error: no matching function for call to 'TestFunction<int, double>(Test()::<lambda(int, double)>&)'
TestFunction<int, double>(fce);
^
main.cpp:106:5: note: candidate: template<class ... TParams> int TestFunction(std::function<void(TParams ...)>)
int TestFunction(std::function<void(TParams...)> fceCallback)
^~~~~~~~~~~~
main.cpp:106:5: note: template argument deduction/substitution failed:
main.cpp:116:31: note: 'Test()::<lambda(int, double)>' is not derived from 'std::function<void(TParams ...)>'
TestFunction<int, double>(fce);
^
A trailing template parameter pack always leaves room for further deduction. Specifying the first two arguments doesn't prevent you from doing something like this:
std::function<void(int, double, char)> fce3 ;
TestFunction<int, double>(fce3);
In this case, the pack will contain int, double, char, because the char was deduced from the function argument. Now, because deduction isn't over, and a lambda is not a std::function, the substitution fails.
To make this work, you need to let the deduction process know it's over, that an instantiated function is needed now, before it's given an argument. One way to do that is to take the function's address, for instance:
auto pfunc = TestFunction<int, double>;
pfunc(fce);
or
(&TestFunction<int, double>)(fce);
Taking a function template's address is another context where template argument deduction can occur. In this case, the trailing pack is deduced as empty, and you get a pointer to a function you may call.
Related
As part of a bigger project, I'm playing with std::tuple and templates; consider the following code:
template <typename ...T> void foo(tuple<T...> t) {}
void bar(tuple<int, char> t) {}
tuple<int, char> quxx() { return {1, 'S'}; }
int main(int argc, char const *argv[])
{
foo({1, 'S'}); // error
foo(make_tuple(1, 'S')); // ok
bar({1, 'S'}); // ok
quxx(); // ok
return 0;
}
According to this answer C++17 supports tuple initialization from copy-list-initialization, however it seems such support is limited since I get the following error (GCC 7.2.0):
main.cpp: In function 'int main(int, const char**)':
main.cpp:14:17: error: could not convert '{1, 'S'}' from '<brace-enclosed initializer list>' to 'std::tuple<>'
foo({1, 'S'}); // error
^
Is there any way I can use brace-enclosed syntax in this scenario?
Some Context : this is going to be used in an operator overload so I guess I'm bound to tuples and cannot make use of variadics, any hint is well-accepted.
Extra : Clang 6 also complains
prog.cc:12:5: error: no matching function for call to 'foo'
foo({1, 'S'}); // error
^~~
prog.cc:6:31: note: candidate function [with T = <>] not viable: cannot convert initializer list argument to 'tuple<>'
template <typename ...T> void foo(tuple<T...> t) {}
A braced-init-list, like {1, 'S'}, does not actually have a type. In the context of template deduction, you can only use them in certain cases - when deducing against initializer_list<T> (where T is a function template parameter) or when the corresponding parameter is already deduced by something else. In this case, neither of those two things is true - so the compiler cannot figure out what ...T is supposed to be.
So you can provide the types directly:
foo<int, char>({1, 'S'});
Or you can construct the tuple yourself and pass that in:
foo(std::tuple<int, char>(1, 'S')); // most explicit
foo(std::tuple(1, 'S')); // via class template argument deduction
Today, ClassTemplate<Ts...> can only be deduced from expressions of type ClassTemplate<Us...> or types that inherit from something like that. A hypothetical proposal could extend that to additionally try to perform class template argument deduction on the expression to see if that deduction succeeds. In this case, {1, 'S'} isn't a tuple<Ts...> but tuple __var{1, 'S'} does successfully deduce tuple<int, char> so that would work. Such a proposal would also have to address issues like... what if we're deducing ClassTemplate<T, Ts...> or any minor variation, which isn't something that class template argument deduction allows (but is something that many people have at times expressed interest in being able to do).
I'm not aware of such a proposal today.
According to this answer C++17 supports tuple initialization from copy-list-initialization, however it seems such support is limited since I get the following error
The problem is another.
When you call bar({1, 'S'}), the compiler knows that bar() receive a tuple<int, char>, so take 1 as int and 'S' as char.
See another example: if you define
void baz (std::tuple<int> const &)
{ }
you can call
baz(1);
because the compiler knows that baz() receive a std::tuple<int> so take 1 to initialize the int in the tuple.
But with
template <typename ...T>
void foo(tuple<T...> t)
{ }
the compiler doesn't know the T... types; when you call
foo({1, 'S'});
what T... types should deduce the compiler?
I see, at least, two hypothesis: T = int, char or T = std::pair<int, char>; or also T = std::tuple<int, char>.
Which hypothesis should follows the compiler?
I mean: if you pass a std::tuple to foo(), the compiler accept the list of types in the tuple as the list of T...; but if you pass something else, the compiler must deduce the correct std::tuple; but this deduction, in this case, is not unique. So the error.
This question is spawned from
Passing a member function pointer to an overloaded class method into a template function.
You need not read that to understand this question. Probably both the questions will have the same answer.
I am getting compiler error for below simple code.
#include<set>
template<typename Return, typename T>
T ReceiveFuncPtr (Return (T::*Method)(const int&))
{
T obj; // Found and declared an object of actual container class
(obj.*Method)(1); // Some processing
return obj; // Returned that container class object with RVO
}
int main ()
{
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
}
The error is interesting:
In function 'int main()':
error: no matching function for call to 'ReceiveFuncPtr(<unresolved overloaded function type>)'
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
^
note: candidate is:
note: template<class Return, class T> T ReceiveFuncPtr(Return (T::*)(const int&))
T ReceiveFuncPtr (Return (T::*Method)(const int&))
^
note: template argument deduction/substitution failed:
note: mismatched types 'const int&' and 'std::initializer_list<int>'
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
^
note: mismatched types 'const int&' and 'std::set<int>::const_iterator {aka std::_Rb_tree_const_iterator<int>}'
note: mismatched types 'const int&' and 'std::set<int>::const_iterator {aka std::_Rb_tree_const_iterator<int>}'
note: mismatched types 'const int&' and 'std::set<int>::value_type&& {aka int&&}'
note: couldn't deduce template parameter 'Return'
If you look at the notes closely then it appears that compiler is matching all the other methods except the right one! In this case compiler should have matched insert(const std::set<int>::value_type&) aka const int&. If I change the ReceiveFuncPtr() to match some other overload, it will again fail by skipping that overload.
To debug this situation, I created handcrafted version of std::set. But that compiles fine:
template<typename T, typename T2 = void>
struct MySet
{
std::pair<T,bool> insert (const T& i) { return std::pair<T,bool>(T(),true); }
std::pair<T,bool> insert (T&& i) { return std::pair<T,bool>(T(),true); }
void insert (std::initializer_list<T> i) { return false; }
}
int main ()
{
ReceiveFuncPtr(&MySet<int>::insert); // OK
}
After surfing, I came across this post:
What are the rules for function pointers and member function pointers to Standard functions?
Though it's related , it doesn't solve problem.
Question: Why member function substitution fails in case of standard library method when the the same thing passes for handwritten class method?
Update:
After looking at the correct answer, I am sure that insert cannot be used. The only way would be ugly typecasting which is an overkill for this problem.
One elegant solution is to use std::set<int>::emplace<const int&> which has only templated version unlike insert which has mix of template and non-template versions.
Call the function as below:
ReceiveFuncPtr(&std::set<int>::emplace<const int&>);
Above compiles fine.
The problem isn't with the insert functions you showed in MySet. The problem is with one of the ones you omitted. Specifically:
template< class InputIt >
void insert( InputIt first, InputIt last );
From [temp.deduct.call]:
When P is a function type, pointer to function type, or pointer to member function type:
— If the argument is an overload set containing one or more function templates, the parameter is treated
as a non-deduced context.
Since &std::set<int>::insert is precisely such an overload set, the parameter is a non-deduced context and cannot be resolved. Your example of MySet does not contain a function template overload for insert, which is why it works fine. If you add one, you'll see that it will also fail to compile.
This question is spawned from
Passing a member function pointer to an overloaded class method into a template function.
You need not read that to understand this question. Probably both the questions will have the same answer.
I am getting compiler error for below simple code.
#include<set>
template<typename Return, typename T>
T ReceiveFuncPtr (Return (T::*Method)(const int&))
{
T obj; // Found and declared an object of actual container class
(obj.*Method)(1); // Some processing
return obj; // Returned that container class object with RVO
}
int main ()
{
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
}
The error is interesting:
In function 'int main()':
error: no matching function for call to 'ReceiveFuncPtr(<unresolved overloaded function type>)'
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
^
note: candidate is:
note: template<class Return, class T> T ReceiveFuncPtr(Return (T::*)(const int&))
T ReceiveFuncPtr (Return (T::*Method)(const int&))
^
note: template argument deduction/substitution failed:
note: mismatched types 'const int&' and 'std::initializer_list<int>'
ReceiveFuncPtr(&std::set<int>::insert); // ERROR
^
note: mismatched types 'const int&' and 'std::set<int>::const_iterator {aka std::_Rb_tree_const_iterator<int>}'
note: mismatched types 'const int&' and 'std::set<int>::const_iterator {aka std::_Rb_tree_const_iterator<int>}'
note: mismatched types 'const int&' and 'std::set<int>::value_type&& {aka int&&}'
note: couldn't deduce template parameter 'Return'
If you look at the notes closely then it appears that compiler is matching all the other methods except the right one! In this case compiler should have matched insert(const std::set<int>::value_type&) aka const int&. If I change the ReceiveFuncPtr() to match some other overload, it will again fail by skipping that overload.
To debug this situation, I created handcrafted version of std::set. But that compiles fine:
template<typename T, typename T2 = void>
struct MySet
{
std::pair<T,bool> insert (const T& i) { return std::pair<T,bool>(T(),true); }
std::pair<T,bool> insert (T&& i) { return std::pair<T,bool>(T(),true); }
void insert (std::initializer_list<T> i) { return false; }
}
int main ()
{
ReceiveFuncPtr(&MySet<int>::insert); // OK
}
After surfing, I came across this post:
What are the rules for function pointers and member function pointers to Standard functions?
Though it's related , it doesn't solve problem.
Question: Why member function substitution fails in case of standard library method when the the same thing passes for handwritten class method?
Update:
After looking at the correct answer, I am sure that insert cannot be used. The only way would be ugly typecasting which is an overkill for this problem.
One elegant solution is to use std::set<int>::emplace<const int&> which has only templated version unlike insert which has mix of template and non-template versions.
Call the function as below:
ReceiveFuncPtr(&std::set<int>::emplace<const int&>);
Above compiles fine.
The problem isn't with the insert functions you showed in MySet. The problem is with one of the ones you omitted. Specifically:
template< class InputIt >
void insert( InputIt first, InputIt last );
From [temp.deduct.call]:
When P is a function type, pointer to function type, or pointer to member function type:
— If the argument is an overload set containing one or more function templates, the parameter is treated
as a non-deduced context.
Since &std::set<int>::insert is precisely such an overload set, the parameter is a non-deduced context and cannot be resolved. Your example of MySet does not contain a function template overload for insert, which is why it works fine. If you add one, you'll see that it will also fail to compile.
I am trying to understand why std::function is not able to distinguish between overloaded functions.
#include <functional>
void add(int,int){}
class A {};
void add (A, A){}
int main(){
std::function <void(int, int)> func = add;
}
In the code shown above, function<void(int, int)> can match only one of these functions and yet it fails. Why is this so? I know I can work around this by using a lambda or a function pointer to the actual function and then storing the function pointer in function. But why does this fail? Isn't the context clear on which function I want to be chosen? Please help me understand why this fails as I am not able to understand why template matching fails in this case.
The compiler errors that I get on clang for this are as follows:
test.cpp:10:33: error: no viable conversion from '<overloaded function type>' to
'std::function<void (int, int)>'
std::function <void(int, int)> func = add;
^ ~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_03:1266:31: note:
candidate constructor not viable: no overload of 'add' matching
'std::__1::nullptr_t' for 1st argument
_LIBCPP_INLINE_VISIBILITY function(nullptr_t) : __f_(0) {}
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_03:1267:5: note:
candidate constructor not viable: no overload of 'add' matching 'const
std::__1::function<void (int, int)> &' for 1st argument
function(const function&);
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_03:1269:7: note:
candidate template ignored: couldn't infer template argument '_Fp'
function(_Fp,
^
1 error generated.
EDIT - In addition to MSalters' answer, I did some searching on this forum and found the exact reason why this fails. I got the answer from Nawaz's reply in this post.
I have copy pasted from his answer here:
int test(const std::string&) {
return 0;
}
int test(const std::string*) {
return 0;
}
typedef int (*funtype)(const std::string&);
funtype fun = test; //no cast required now!
std::function<int(const std::string&)> func = fun; //no cast!
So why std::function<int(const std::string&)> does not work the way funtype fun = test works above?
Well the answer is, because std::function can be initialized with any object, as its constructor is templatized which is independent of the template argument you passed to std::function.
It's obvious to us which function you intend to be chosen, but the compiler has to follow the rules of C++ not use clever leaps of logic (or even not so clever ones, as in simple cases like this!)
The relevant constructor of std::function is:
template<class F> function(F f);
which is a template that accepts any type.
The C++14 standard does constrain the template (since LWG DR 2132) so that it:
shall not participate in overload resolution unless f is Callable (20.9.12.2) for argument types ArgTypes... and return type R.
which means that the compiler will only allow the constructor to be called when Functor is compatible with the call signature of the std::function (which is void(int, int) in your example). In theory that should mean that void add(A, A) is not a viable argument and so "obviously" you intended to use void add(int, int).
However, the compiler can't test the "f is Callable for argument types ..." constraint until it knows the type of f, which means it needs to have already disambiguated between void add(int, int) and void add(A, A) before it can apply the constraint that would allow it to reject one of those functions!
So there's a chicken and egg situation, which unfortunately means that you need to help the compiler out by specifying exactly which overload of add you want to use, and then the compiler can apply the constraint and (rather redundantly) decide that it is an acceptable argument for the constructor.
It is conceivable that we could change C++ so that in cases like this all the overloaded functions are tested against the constraint (so we don't need to know which one to test before testing it) and if only one is viable then use that one, but that's not how C++ works.
While it's obvious what you want, the problem is that std::function cannot influence overload resolution of &add. If you were to initialize a raw function pointer (void (*func)(int,int) = &add), it does work. That's because function pointer initialization is a context in which overload resolution is done. The target type is exactly known. But std::function will take almost any argument that's callable. That flexibility in accepting arguments does mean that you can't do overload resolution on &add. Multiple overloads of add might be suitable.
An explicit cast will work, i.e. static_cast<void(*)(int, int)> (&add).
This can be wrapped in a template<typename F> std::function<F> make_function(F*) which would allow you to write auto func = make_function<int(int,int)> (&add)
Try:
std::function <void(int, int)> func = static_cast<void(*)(int, int)> (add);
Addresses to void add(A, A) and void add(int, int) obvoiusly differes. When you point to the function by name it is pretty much imposible for compiler to know which function address do you need. void(int, int) here is not a hint.
Another way to deal with this is with a generic lambda in C++14:
int main() {
std::function<void(int, int)> func = [](auto &&... args) {
add(std::forward<decltype(args)>(args)...);
};
}
That will create a lambda function that will resolve things with no ambiguity.
I did not forward arguments,
As far as I can see, it's a Visual Studio problem.
c++11 standard (20.8.11)
std::function synopsis
template<class R, class... ArgTypes> class function<R(ArgTypes...)>;
but VisualStudio doesn't have that specialization
clang++ and g++ are perfectly fine with overloading std::functions
prior answers explain why VS doesn't work, but they didn't mention that it's VS' bug
I've got a question about how to properly use the new C++11 std::function variable. I've seen several examples from searching the Internet, but they don't seem to cover the usage case I'm considering. Take this minimum example, where the function fdiff is an implementation of the finite forward differencing algorithm defined in numerical.hxx (which isn't the problem, I just wanted to give a contextual reason why I'd want to take an arbitrary function and pass it around).
#include <functional>
#include <iostream>
#include <cmath>
#include "numerical.hxx"
int main()
{
double start = 0.785398163;
double step = 0.1;
int order = 2;
std::function<double(double)> f_sin = std::sin;
std::cout << fdiff(start, step, order, f_sin) << std::endl;
return 0;
}
Attempting to compile the above program gives me the error (in clang++)
test.cpp:11:32: error: no viable conversion from '<overloaded function type>' to
'std::function<double (double)>'
std::function<double(double)> f_sin = std::sin;
^ ~~~~~~~~
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/functional:2048:7: note:
candidate constructor not viable: no overload of 'sin' matching
'nullptr_t' for 1st argument
function(nullptr_t) noexcept
^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/functional:2059:7: note:
candidate constructor not viable: no overload of 'sin' matching 'const
std::function<double (double)> &' for 1st argument
function(const function& __x);
^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/functional:2068:7: note:
candidate constructor not viable: no overload of 'sin' matching
'std::function<double (double)> &&' for 1st argument
function(function&& __x) : _Function_base()
^
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../include/c++/4.7.1/functional:2092:2: note:
candidate template ignored: couldn't infer template argument '_Functor'
function(_Functor __f,
^
1 error generated.
or from g++
test.cpp: In function ‘int main()’:
test.cpp:11:45: error: conversion from ‘<unresolved overloaded function type>’ to non-scalar type ‘std::function<double(double)>’ requested
As I understand the problem, it's because std::sin is implemented as a template class in the standard library, but I can't seem to figure out what I need to do to give enough of a specialization to get a function reference. I've also tried various things like using the new auto keyword, using &std::sin to get a pointer, etc., but they all give me the same type of error.
std::sin is an overloaded function: you must disambiguate which std::sin overload you mean:
std::function<double(double)> f_sin = (double(*)(double))&std::sin;
There are some cases where the compiler can disambiguate overloaded functions (e.g., if f_sin was of type double(*)(double), the cast would not be required). However, this is not one of those cases.
With lambda you will be always on safe side:
std::function<double(double)> f_sin = [](double arg) -> double { return std::sin(arg); };
Actually you can do better, if you can change fdiff or it is already accepting template parameter - not just std::function<double(double)>:
auto f_sin = [](double arg) -> double { return std::sin(arg); };
std::cout << fdiff(start, step, order, f_sin) << std::endl;
[UPDATE] This answer is new version, previous advice to use function template specialization was incorrect, since std::sin is not function template but set of overloaded functions.