Reputation: 43
I am trying to implement a JavaScript map function in C++ but cannot get it to accept a lambda. It works when I use a function pointer but not with a lambda. I understand that a lambda and a function pointer are different; I just don't understand why the foreach function is fine but the map function is not.
Any help you will be very appreciated.
template<typename T>
struct List {
void* buffer;
...
void each(void(func)(T))
{
for (u32 index = 0; index < size; index += 1)
{
func(((T*)buffer)[index]);
}
}
template <typename OutType>
List<OutType> map(OutType(func)(T))
{
List<OutType> list;
for (u32 index = 0; index < size; index += 1)
{
list.push(func(((T*)buffer)[index]));
}
return list;
}
};
Usage Code:
i64 addTwo(i32 n)
{
return (i64)(n + 2);
}
int main()
{
List<i32> list;
list.push(4);
list.push(2);
// works
list.each([](i32 num) {
std::cout << num << std::endl;
});
// works
auto list1 = list.map(addTwo);
// does not work
auto list2 = list.map([](i32 n) -> i32 {
return n + 3;
});
}
Error Output:
.../main.cpp:53:23: error: no matching member function for call to 'map'
auto list2 = list.map([](i32 n) -> i32 {
~~~~~^~~
.../list.hpp:86:19: note: candidate template ignored: could not match 'OutType (*)(int)' against
'(lambda at /home/caleb/opengl-starter/source/main.cpp:53:27)'
List<OutType> map(OutType(func)(T))
^
1 error generated.
Upvotes: 3
Views: 100
Reputation: 41780
Your function should simply accept a simple type:
template <typename F, typename OutType = std::invoke_result_t<F, T const&>>
auto map(F function) -> List<OutType>
{
List<OutType> list;
for (u32 index = 0; index < size; index += 1)
{
list.push(function(((T*)buffer)[index]));
}
return list;
}
That way, F
can be a lambda, a function pointer or any other callable type that can recieve T
.
If F
would resolve into any other type that is not callable with a T
, it would be a substitution error.
Upvotes: 6
Reputation: 41100
In this case you can coerce your lambda into a function pointer:
auto list2 = list.map(+[](i32 n) -> i32 {
return n + 3;
});
This only works because the lambda doesn't capture anything. In the general case, your template should distinguish between function pointers and callable things (things with an operator()
defined).
here's a thorough explanation for why prepending +
to the lambda works
Upvotes: 5