Adding a mapping function to a vector in C ++ 11

I have a custom vector class that for all purposes and tasks acts like std :: vector. I want to add a simple map function:

template <class T> class Vector { public: template<class mapFunction> Vector<typename mapFunction::result_type> map(mapFunction function) { Vector<mapFunction::result_type> result(_Length); for(UINT i = 0; i < _Length; i++) { result[i] = function(_Data[i]); } return result; } ... } 

Using:

 Vector<int> v(5); for(int i = 0; i < 5; i++) v[i] = i; auto mappedVector = v.map(function<double(int)>([](int a) { return a * 2.0; })); 

This works, but I try to avoid the need to cast an expression from a lambda expression to std::function . Ideally, this would be just v.map([](int a) { return a * 2.0; })); I understand that probably I could write a "make_function" like "make_pair" to avoid the need for template parameters, but you still need to discard all your lambdas.

I passed it to std::function because I don't know how to extract the return type from the raw lambda type; so i am using std::function::result_type .

I thought the following would work, but it wasn’t - the compiler simply complains that it cannot output the template argument for "returnType":

 template<class mapFunction, class returnType> Vector<returnType> Map2(mapFunction function) { Vector<returnType> result(_Length); for(UINT i = 0; i < _Length; i++) { result[i] = function(_Data[i]); } return result; } 

I understand that std::transform does this (I can easily replace the map body with a call to std::transform ), but my problem is really with the correct way to specify template parameters.

+4
source share
1 answer

First of all, do not use std::function for these problems.


I will give you an example first, and I will give a brief explanation. Please note that I used std::vector to store data and provide functionality, since I really do not want to implement the entire Vector class myself;).

LIFE WORK CODE

 #include <iostream> #include <vector> // /---------------------------------------------------------\ // | // | template<typename T> // | class Vector { // | public: // | std::vector<T> data; // | // | template<class mapFunction> // | // Below: use C++11 trailing return type | auto map(mapFunction function) -> Vector<decltype(function(std::declval<T>()))> // | | { // | | // \-----------------------------------/ // | // | // /-----------------------------------\ // | | using ReturnType = decltype(function(std::declval<T>())); Vector<ReturnType> result; auto size = data.size(); result.data.reserve(size); for(std::size_t i = 0; i < size; i++) { result.data.push_back(function(data[i])); } return result; } }; int main() { Vector<int> v; for(int i = 0; i < 10; ++i) { v.data.push_back(i); } auto newV = v.map([](int i) -> float { return (i * 2.0f) + 0.5f; // Multiply by 2 and add 0.5 }); for(auto e : newV.data) { std::cout << e << std::endl; } } 

First, it uses a C ++ 11 return type return function. We need to do this because we need to refer to the function parameter. The decltype(function(std::declval<T>())) part decltype(function(std::declval<T>())) is the one who is interesting. In this we basically request the compiler

"What will be the return type of the function given the value of an argument of type T ?"

Then the compiler returns the return type and what we give to the first parameter of our Vector result.

The later parts have the same essence as yours, although I changed them for correctness and elegance.

Note that in C ++ 14 you can remove the return return type and just

 template<class mapFunction> auto map(mapFunction function) { using ReturnType = decltype(function(std::declval<T>())); Vector<ReturnType> result; ... return result; } 
+10
source

Source: https://habr.com/ru/post/1502948/


All Articles