How to define template parameters for a generic lambda argument? [duplicate] - c++

This question already has an answer here:
Constructing std::function argument from lambda
(1 answer)
Closed 3 years ago.
Explanation:
CLion and it's standard compiler give me an error that the "candidate template [is] ignored", when I write a lambda as parameter for a generic function that takes a lambda as argument.
This lambda takes a generic type T and returns another unknown type A.
The container class that I am writing is supposed to support functional operations like these in Scala or the ones from the Java Stream API.
To be exact:
The map function makes huge problems. It is implemented as a member function in a class called Sequence, which takes a generic parameter T.
It is supposed to take an element of an already known type T ( actually it iterates through the whole sequence ) and convert it into an unknown type A.
The implementation itself is not the problem, but I cannot call the function with the lambda syntax I know.
Code:
Sequence.h
template< typename T >
class Sequence {
public:
template< typename A >
auto map( std::function< A( const T ) > function ) const {
auto sequence = new Sequence< A >;
for ( const T& element : *this ) {
sequence->push( function( element ) );
}
return *sequence;
}
}
main.cpp
int main() {
Sequence< uint32_t > a;
a.push( 20 );
a.push( 30 );
a.push( 40 );
a.map( []( uint32_t c ) -> uint32_t {
return c * c;
} );
return 0;
}
As far as I understand a lambda gets initialized, which
takes a parameter of type std::uint32_t and returns a value of type std::uint32_t.
The generic parameter A doesn't seem to get inferred at this point.
Error Stack:
main.cpp:21:7: error: no matching function for call to 'Sequence<unsigned int>::map(main()::<lambda(uint32_t)>)'
} );
Sequence.h:143:10: note: candidate: template<class A> auto Sequence<T>::map(std::function<A(T)>) const [with A = A; T = unsigned int]
auto map( std::function< A( const T ) > function ) const {
note: template argument deduction/substitution failed:
main.cpp:21:7: note: 'main()::<lambda(uint32_t)>' is not derived from 'std::function<A(unsigned int)>'
} );
Thanks in advance!

Ignoring the const problem, you have a sort of chicken-and-egg problem.
It's true that your lambda can be converted to a std::function<std::uint32_t(std::unit32_t)>.
But it's also true that the lambda isn't a std::function<std::uint32_t(std::unit32_t)> so the compiler can't deduce A.
And if the compiler can't deduce A, can't convert the lambda to std::function<A(T)>.
You obviously can explicit the correct std::function type calling map()
a.map(std::function<std::uint32_t(std::uint32_t)>{[]( uint32_t c ) -> uint32_t {
return c * c;
}});
and, taking in count that you're using C++17 (so you can use the deduction guides for std::function) also deducing the template parameters for std::function
a.map(std::function{[]( uint32_t c ) -> uint32_t {
return c * c;
}});
but, using again the template deduction guides for std::function, what about writing mat() to accept a simply callable and deducing A from it?
I mean... what about something as follows?
template <typename F>
auto map( F && func ) const {
using A = typename decltype(std::function{std::forward<F>(func)})::result_type;
auto sequence = new Sequence< A >;
for ( const T& element : *this ) {
sequence->push( std::forward<F>(func)( element ) );
}
return *sequence;
}
(caution: code not tested).
You can also deduce A, without std::function deduction guides (so before C++17), as suggested by Michael Kenzel.

As already pointed out by #cpplearner in the comments above, the reason why this won't work is explained in detail here: Constructing std::function argument from lambda.
If your Sequence is already a template, there should be no reason to require the callable for your map function to be passed in the form of an std::function. At least, I seem unable to come up with a reason that could justify doing this. std::function is generally not free to construct or call, and also can inhibit inlining. Best avoid it unless you really need the capability to store arbitrary callables for later use. Simply take a forwarding reference, e.g.:
template <typename F>
auto map(F&& f) const;
You should be able to deduce the result type of whatever invoking f on an element of your sequence ends up producing, e.g., via
decltype(f(std::declval<T>()))
Furthermore, don't just return a raw pointer to a new Sequence. Use an std::unique_ptr.
Putting it all together, your map function could look something like this:
template <typename F>
auto map(F&& f) const
{
using output_element_type = decltype(f(std::declval<T>()));
auto sequence = std::make_unique<Sequence<output_element_type>>();
for (const T& element : *this)
sequence->push(f(element));
return sequence;
}

Related

Using a template with lambda function pointer

I'm playing around with some C++11 features, and I encountered the following:
#include <iostream>
#include <vector>
template <class T>
void map(std::vector<T>& values, T(*func)(T)) {
for (int &value : values) {
value = func(value);
}
}
int mul2(int x) {
return 2*x;
}
auto mul3 = [](int value) {
return value * 3;
};
int main() {
std::vector<int> v = { 1,2,3,4,5 };
map(v, mul3);
for (auto value : v) {
std::cout << value << std::endl;
}
}
using map with mul2 works as expected, but when I use the mul3 function it gives a compilation error. I expected that auto in this case would give me a int function pointer, but it seems that is not the case here. Anybody could explain this behaviour?
The lambda can implicitly be converted to a function pointer, but that's not what's failing here. Rather, the compiler is failing to deduce T because the lambda-to-function-pointer conversion doesn't happen during deduction.
main.cpp:5:6: note: template argument deduction/substitution failed:
main.cpp:21:16: note: mismatched types 'T (*)(T)' and '<lambda(int)>'
21 | map(v, mul3);
| ^
The compiler can make the connection between T(*)(T) and int(*)(int) and it can make the connection between int(*)(int) and the lambda type, but it can't make the connection between T(*)(T) and the lambda type.
You can fix this by making one of the two connections for it: explicitly specifying the function's template argument, or casting the lambda to the function pointer type. The first skips the deduction step an then the implicit lambda-to-function-pointer conversion succeeds. The second allows deduction to succeed because the second parameter is a compatible function pointer type.
// Option 1: Specifying T allows implicit conversion of the lambda to fnptr
map<int>(v, mul3);
// Option 2a: Cast of lambda to fnptr allows T to be deduced
map(v, static_cast<int(*)(int)>(mul3));
// Option 2b: Converting lambda to fnptr at mul3 initialization allows T to be deduced
int (*mul3)(int) = [](int value) {
return value * 3;
};
However, I would recommend fixing the issue a different way -- there's no reason the function has to work with vectors, function pointers, and ints. Why can't it work with linked lists, functors, and doubles? There's really no reason to constrain the types like this; just let them be whatever they are and see if the instantiation succeeds:
template <class TContainer, TFunction>
void map(TContainer & values, TFunction const & func) {
for (auto &value : values) {
value = func(value);
}
}
Expanded from my comment (when the question was closed), you can template away the function details using the functor template "pattern":
template <class T, typename Functor>
void map(std::vector<T>& values, Functor func) {
for (int &value : values) {
value = func(value);
}
}
See here for full example: https://godbolt.org/z/fdHvAP

Member function template deduction guide or other method to let the compiler know how to call function

struct setup_entry
{
template< typename T >
void Disable( bool(*p)(T*) ) { ... }
}
Calling Disable:
setup_entry X;
Case 1: X.Disable( [](int*)->bool{...} ); //FAIL to deduce T
Case 2: X.Disable<int>( [](int*)->bool{...} ); //OK to deduce T
I would like to use case 1. (Easier for the user)
Any ideas?
The simplified final solution for the record was to do this:
template< typename T >
void Disable( T&& Callback )
{
auto p = +Callback;
...
}
You can't do that because implicit conversion (from lambda to function pointer) won't be considered in template argument deduction; T can't be deduced.
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
If you want to stick to auto type deduction, you can convert the lambda to function pointer explicitly, e.g.
X.Disable(+[](int*)->bool{...} );
// ^
Or
X.Disable(static_cast<bool(*)(int*)>([](int*)->bool{...}));
First you should know that the type of [](int*) -> bool {...} is not just bool(int*) or bool(*)(int*); it is a unique closure type convertible to bool(*)(int*).
And this type is not deducible in this context.
A solution: explicitly do the conversion.
X.Disable( static_cast<bool(*)(int*)>([](int*) -> bool {...}) );
Better solution: as #Some programmer dude says, use a template or use std::function. For example:
template <typename F>
void Disable(F f)
{
static_assert(std::is_invocable_r_v<bool, F, int*>, "your message here"); // if you want to ensure that the function is actually valid
// ...
}
Or:
void Disable(std::function<bool(int*)> f) { ... }

Deducing template parameter from functor argument type [duplicate]

This question already has answers here:
Is it possible to figure out the parameter type and return type of a lambda?
(5 answers)
Closed 7 years ago.
I have the following code that is meant to accept a Qt QVariant and apply a functor if the variant contains a value:
template<typename T, typename Functor>
inline QVariant map(const QVariant& v, Functor f)
{
return v.isValid()
? QVariant{f(qvariant_cast<T>(v))}
: v;
}
My problem is that the compiler cannot deduce the type of T when I invoke this function as
map(someFuncReturningQVariant(), [](const QByteArray& array) -> QString {
return array.toString();
});
The compiler complains (cleaned up from the original error, which has longer type names):
error: no matching function for call to `map(QVariant, <lambda(const QByteArray&)>)`
note: candidate is:
template<class T, class Functor> QVariant map(const QVariant&, Functor).
note: template argument deduction/substitution failed:
couldn't deduce template parameter 'T'
This is because QVariant erases the type of the object it contains at runtime. (It still knows it internally, much like boost::any, and qvariant_cast<T>() gets the original object back).
How can I capture the type of the variable passed to the Functor and use it elsewhere? Alternatively, how can I specify that Functor takes a parameter of type T? (I suspect these are actually the same question, or that they at least have the same answer.)
Note that my approach works fine with std::optional, because the types are not erased:
using std::experimental::optional;
template<typename T, typename Functor>
inline auto map(const optional<T>& v, Functor f) -> optional<decltype(f(*v))>
{
return v ? optional<decltype(f(*v))>{f(*v)}
: v;
}
Also note that the QVariant code works fine if I manually specify the type:
map<QByteArray>(someFuncReturningQVariant(), [](const QByteArray& array) -> QString {
return array.toString();
});
But of course, this is much uglier.
Basically what you want is: given a functor, F, identify the decayed type of its first argument.
To that end, we need function_traits, with which we can do:
template <typename F>
using first_arg = std::decay_t<typename function_traits<F>::template arg<0>::type>;
Which we use:
template<typename Functor>
inline QVariant map(const QVariant& v, Functor f)
{
using T = first_arg<Functor>;
return v.isValid()
? QVariant{f(qvariant_cast<T>(v))}
: v;
}
map<QByteArray>(someFuncReturningQVariant(), [](auto&& array){
return array.toString();
});
is the C++14 way to do that: don't specify the type in the lambda, but rather as (only) a template parameter.
Also note ->QString is redundant in C++11 or 14.
Alternatively, know that QVariant is not a type ameniable to mapping. Do the cast explicitly external to your map function.
Map the QVariant to a optional<T&> externally (or a T*), and return an optional<std::result_of_t<F(T&)>> (or a QVariant if you like throwing away information).

Using a type that depends on lambda function as a return type

I want to make a function that takes a lambda as parameter, and returns an object which type depends on the lambda function return type.
What I'm trying to achieve is essentially no explicit template parameter at instantiation.
For now, here is my solution, and my question is: is there a shorter (and more elegant) way to do it ?
template<typename Func, typename RT = std::unordered_map<int,
decltype(((Func*)nullptr)->operator()(T())) > >
RT mapResult(Func func)
{
RT r;
for (auto &i : mData)
r.insert({i.first, func(mData.second)});
return r;
}
To make it a little more clear, the lambda type Func takes T& as parameter and returns a vector of a certain type, and mapResult maps the result of func in an unordered_map whose _Ty template parameter is the lambda function return type (potentially something else, but still dependent on this type). The actual code is much more complicated, but I'm trying to gain clarity on this point specifically.
The only solution I found to avoid writing the RT type several times was to put it in the template parameters list and give it a default value, dependent on the first template parameter (which itself is deduced from the function argument). It's a little like defining a templated typename.
I'm using VC12, but want to have portable code that compiles under g++ as well.
The instantiation then looks like this (dummy example):
auto r = c.mapResult([](T &t){return std::vector<int> {(int)t.size()};});
The C++11 Standard Library contains a metafunction called result_of. This metafunction computes the return type of a function object. Probably due to its history in boost (and C++03), it is used in a rather peculiar way: You pass it the type of the function object and the type of the arguments you want to call the function object with via a combined function type. For example:
struct my_function_object
{
bool operator()(int);
char operator()(double);
};
std::result_of<my_function_object(int)>::type // yields bool
std::result_of<my_function_object(short)>::type // yields bool
std::result_of<my_function_object(double)>::type // yields char
result_of performs overload resolution. If you call short s{}; my_function_object{}(s);, overload resolution will select my_function_object::operator()(int). Therefore, the corresponding result_of<my_function_object(short)>::type yields bool.
Using this trait, you can simplify the computation of the return type as follows:
template<typename Func, typename RT = std::unordered_map<int,
typename std::result_of<Func(T&)>::type > >
RT mapResult(Func func)
{
RT r;
for (auto &i : mData)
r.insert({i.first, func(i.second)});
return r;
}
The T& parameter tells result_of to use an lvalue argument in overload resolution. The default (for a non-reference type T) is xvalue (T&&).
There is one slight difference to the OP's version: SFINAE will probably not work correctly using std::result_of (in C++11). This was resolved in C++14. See N3462.
C++14 has introduced standardized alias templates like result_of_t so you can get rid of the typename and ::type:
template<typename Func, typename RT = std::unordered_map<int,
std::result_of_t<Func(T&)> > >
RT mapResult(Func func)
{
RT r;
for (auto &i : mData)
r.insert({i.first, func(i.second)});
return r;
}
If you're using Visual Studio 2013 or newer, you can write alias templates yourself. You could also go one step further and write the whole return type as a metafunction:
template<typename FT> using result_of_t = typename std::result_of<FT>::type;
template<typename Func> using RetType =
std::unordered_map<int, result_of_t<Func(T&)> >;
template<typename Func, typename RT = RetType<Func> >
RT mapResult(Func func)
{
RT r;
for (auto &i : mData)
r.insert({i.first, func(i.second)});
return r;
}
Of course, if you have sufficient C++14 core language support (not in VS12), you can use return type deduction as well:
template<typename Func>
auto mapResult(Func func)
{
auto r = std::unordered_map<int, result_of_t<Func(T&)>>{};
for (auto &i : mData)
r.insert({i.first, func(i.second)});
return r;
}
It is also possible to shorten a version using decltype:
using std::declval;
decltype(declval<Func>(T{}))
although this isn't quite correct, both the function object and the argument will be an lvalue:
decltype(declval<Func&>(declval<T&>{}))
declval will use an xvalue in overload resolution for a non-reference type X. By adding the &, we tell it to use an lvalue instead. (result_of is based on declval, so both show this behaviour.)
Note that in any case, it might be useful to run the result_of_t<Func(T&)> type through the std::decay metafunction, to get rid e.g. of references which appear in cases such as:
[](string const& s) -> string const& { return s; } // identity
This does depend on your use case though, and either choice should be documented.
IIRC, emplace is slightly more efficient (in theory) in this situation (inserting unique elements):
r.emplace(i.first, func(i.second));
It might be possible to further optimize this function, e.g. by reserving a bucket count before the insertion, or maybe with an iterator adapter to leverage the constructor for insertion. Using std::transform should also be possible, though I'd guess it cannot be as efficient due to additional moves of the value_type pair.
In C++11 there are few things that you can do to make it sorter. One way is to use template aliases:
namespace details
{
template <typename Func>
using map_type_t =
std::unordered_map<int, typename std::result_of<Func(T)>::type>>;
}
template <typename Func>
details::map_type_t<Func> mapResult(Func func)
{
details::map_type_t<Func> r;
//...
return r;
}
In C++14 you can leave the return type deduction to the compiler:
template <typename Func>
auto mapResult(Func func)
{
std::unordered_map<int, decltype(func(T()))> r;
//...
return r;
}

Is it possible to allow one std::function type accept lambdas with different signatures

I have a higher order function map which is similar to STL for_each, and maps a std::function object over a vector of things.
template<class T, class U>
vector<U> map(function<U (T)> f, vector<T> xs) {
vector<U> ret;
for (auto &x: xs)
ret.push_back(f(x));
return ret;
}
Now, I want to have this higher order function take both objects of types function<int (const vector<T>&)> and function<int (vector<T>)>, as shown in the attached minimal example.
The problem is that function<int (const vector<T>&)> and function<int (vector<T>)> seem to be convertible to each other (see head and head2), but map won't take the const references version function<int (const vector<int>&)> (see Q1).
It is possible to tell map to accept the const reference version with explicit conversion (Q2), but this is rather cumbersome.
I was wondering if, in general, it is possible to write a function deref that removes the const reference from function<int (const vector<T>&)> and returns a function<int (vector<T>)>?
(If above is possible, then I won't have to write two identical overloads/implementations of map for const refs).
Thanks.
#include <vector>
#include <functional>
using namespace std;
template<class T, class U>
vector<U> map(function<U (T)> f, vector<T> xs) {
vector<U> ret;
for (auto &x: xs)
ret.push_back(f(x));
return ret;
}
int main() {
vector<vector<int>> m;
function<int (const vector<int>&)> head = [](const vector<int>& a) {return a[0];};
function<int (const vector<int>&)> head1 = [](vector<int> a) {return a[0];}; //conversion OK
function<int (vector<int>)> head2 = [](const vector<int>& a) {return a[0];}; //conversion OK
map(head2,m); //OK
map(head,m); //Q1: problem line, implicit conversion NOT OK
map(function<int (vector<int>)>(head),m); //Q2: explicit conversion OK
map(deref(head),m); //Q3: ??How-to, deref takes a std::function f and returns a function with const ref removed from its signature
return 0;
}
--- EDIT ---
I am particularly interested in a deref like function or a meta-function that can remove the const ref from the type signature of a std::function object, so that I can at least do Q2 automatically.
I know that, as #Brian and #Manu correctly pointed out, the use of std::function to specify types is not conventional, but I wonder what I asked above is even feasible. Personally, I think code with std::function has greater clarity, considering how generic function types Func<T1, T2, T3, ...,Tn, Tresult> are used in C#. This is if the cost of type erasure is tolerable.
I fully agree that c++ can infer return types and give an error message when type is wrong. Maybe it's just a matter of taste and I would prefer to spell it out when writing function signatures.
I understand why you are using std::function: You have to know the return type of the transformation to create the vector, right?
But consider a completely different approach. Given the metafunction std::result_of you could compute the result type of a function call, so just write:
template<typename F , typename CONTAINER , typename T = typename std::result_of<F(typename CONTAINER::value_type)>::type>
std::vector<T> map( F f , CONTAINER&& container )
{
std::vector<T> result;
for( auto& e : container )
result.emplace_back( f( e ) );
return result;
}
Advantages:
No abuse of std::function: Always think what std::function does (i.e. type erasure), don't use it as an universal function type.
Rely on duck typing instead of coupling on the types: Don't worry, if something was wrong it wouldn't compile neither.
Works for any Standard Library Container since we extracted the element type with the value_type trait, instead of using std::vector directly.
The code is much more clear and efficient, both because the reduction of std::function usage.
Regarding the question "Its possible to write a function that accepts lambdas of multiple signatures?"
Using std::function you could write something similar to Boost.OverloadedFunction in a couple of lines:
template<typename F , typename... Fs>
struct overloaded_function : public std_function<F> , public std_function<Fs>...
{
overloaded_function( F&& f , Fs&&... fs ) :
std_function<F>{ f },
std_function<Fs>{ fs }...
{}
};
Where std_function is a metafunction which given a function type F returns the std::function instance with the signature of F. I leave it as a game/challenge for the reader.
Thats all. Improve it with a make-like function:
template<typename F , typename... Fs>
overloaded_function<F,Fs...> make_overloaded_function( F&& f , Fs&&... fs )
{
return { std::forward<F>( f ) , std::forward<Fs>( fs )... };
}
And you are ready to go:
auto f = make_overloaded_function( [](){ return 1; } ,
[](int,int){ return 2; } ,
[](const char*){ return 3; } );
f(); //Returns 1
f(1,2); //Returns 2
f("hello"); //Returns 3
EDIT: "Thanks. But, what I am really looking for, is a meta-function that takes the signature of a callable, and removes the const refs from the signature."
Ok, let me try: The std::decay metafunction applies the decaying done when passing argumments by value to a given type. This includes removing cv qualifiers, removing references, etc. So a metafunction like yours could be something that takes a function signature type and applies decaying to all its argumments:
template<typename F>
struct function_decay;
template<typename R typename... ARGS>
struct function_decay<R(ARGS...)>
{
using type = R(typename std::decay<ARGS>::type...);
};
That should do the work.
I have written this because you explicitly asked for it in the comment, but I strongly encourage you to use the alternative I showed you initially, because it has many advantages compared to your way.
That said, I hope this answer helped to solve your problem.
The idiomatic solution is to simply allow map to take an arbitrary function-like type,
template<class T, class F>
auto map(F f, vector<T> xs) -> vector<typename result_of<F(T)>::type> {
vector<typename result_of<F(T)>::type> ret;
for (auto &x: xs)
ret.push_back(f(x));
return ret;
}
The main issue with this approach is that you get confusing error messages if F is not callable with arguments of type T, or if it returns something strange, like void.
(A secondary issue is that the first argument to map can't be an overloaded function; the compiler won't simply be able to pick the overload that takes an argument of type T.)
(You might also want to consider decaying the return type of f.)