I would like to be able to write something like
char f(char);
vector<char> bar;
vector<char> foo = map(f, bar);
The transform
function appears to be similar, but it will not autogenerate the size of the resultant collection.
You can use std::back_inserter
in <iterator>
, although providing the size in front is more efficient. For example:
string str = "hello world!", result;
transform(str.begin(), str.end(), back_inserter(result), ::toupper);
// result == "HELLO WORLD!"
This question was asked before the C++11 standard went into effect... nowadays we have std::transform()
as the (ugly) equivalent of a functional programming 'map'. Here's how to use it:
auto f(char) -> char; // or if you like: char f(char)
vector<char> bar;
vector<char> foo;
// ... initialize bar somehow ...
std::transform(bar.begin(), bar.end(), std::back_inserter(foo), f);
To make this work, you'll need the following observations:
map
function should not do the work. Instead, it should save its arguments in a temporary object (in your case, that would be an instance of class map::result<char(*)(char), vector<char> >
)map::result
temporary should have an template <typename T> operator T
conversion.map::result
is assigned to a std::vector<char>
, this conversion is the only viable.class map::result<char(*)(char), vector<char> >::operator vector<char>
you have the input and return type, and the mapping function. At this point you can effectively transform the inputs.<edit>
template<typename CONT, typename FUNC>
class mapresult {
CONT const& in;
FUNC f;
public:
template<typename RESULT> RESULT to() const
{
RESULT out;
for (auto const& e : in) { out.push_back(f(e)); }
return out;
}
template<typename RESULT> operator RESULT() const
{
return this->to<RESULT>();
}
mapresult(CONT const& in, FUNC f) : in(in), f(std::move(f)) { }
};
template<typename CONT, typename FUNC>
auto map(CONT const& in, FUNC f) -> mapresult<CONT, FUNC>
{
return mapresult<CONT, FUNC>(in, f);
}
using namespace std;
char foo(char c) { return c | ('A' ^ 'a'); }
std::string in = "Test";
int main(int argc, char* argv[])
{
string out = map(in, &foo);
cout << out << endl;
char replace = 'e';
cout << map(in, [replace](char c){return c == replace ? '?' : c; }).to<string>();
}
You can mimic the map syntax above with something like
template<typename T, typename A>
T map(A(*f)(A), T & container) {
T output;
std::transform(container.begin(), container.end(), std::back_inserter(output), f);
return output;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With