Equivalent of python map function using lambda - c++

I am wondering if it is possible to write a C++ equivalent of the Python function map, using the automatic return type deduction feature. What I have in mind is something like this:
vector<int> input({1,2,3});
auto output=apply(input,[](int num){return num*num;});
//output should be a vector {1,4,9}
I do know about std::transform, but in the present state of affairs, writing a range loop seems easier.

Baum mit Augen's answer is most of the way there. Just takes a few more steps to support anything that is for-each-able:
template <typename C, typename F>
auto apply(C&& container, F&& func)
{
using std::begin;
using std::end;
using E = std::decay_t<decltype(std::forward<F>(func)(
*begin(std::forward<C>(container))))>;
std::vector<E> result;
auto first = begin(std::forward<C>(container));
auto last = end(std::forward<C>(container));
result.reserve(std::distance(first, last));
for (; first != last; ++first) {
result.push_back(std::forward<F>(func)(*first));
}
return result;
}
We can even go one step further and make this SFINAE-able by not using C++14 auto deduction and instead moving the failure up to the deduction phase. Start with a helper for begin/end:
namespace adl_helper {
using std::begin;
using std::end;
template <typename C>
auto adl_begin(C&& c) -> decltype(begin(std::forward<C>(c))) {
return begin(std::forward<C>(c));
}
template <typename C>
auto adl_end(C&& c) -> decltype(end(std::forward<C>(c))) {
return end(std::forward<C>(c));
}
}
using adl_helper::adl_begin;
using adl_helper::adl_end;
And then use that to deduce E earlier:
using adl_helper::adl_begin;
using adl_helper::adl_end;
template <typename C,
typename F,
typename E = std::decay_t<decltype(std::declval<F>()(
*adl_begin(std::declval<C>())
))>
>
std::vector<E> apply(C&& container, F&& func)
{
/* mostly same as before, except using adl_begin/end instead
of unqualified begin/end with using
*/
}
Now we can test at compile time if some container/function pair is apply-able, and the error is a deduction failure instead of a usage failre:
int arr[] = {1, 2, 3};
auto x = apply(arr, []{ return 'A'; });
main.cpp: In function 'int main()':
main.cpp:45:52: error: no matching function for call to 'apply(int [3], main()::<lambda()>)'
auto x = apply(arr, []() -> char { return 'A'; });
^
main.cpp:29:16: note: candidate: template<class C, class F, class E> std::vector<E> apply(C&&, F&&)
std::vector<E> apply(C&& container, F&& func)
^
main.cpp:29:16: note: template argument deduction/substitution failed:
main.cpp:25:50: error: no match for call to '(main()::<lambda()>) (int&)'
typename E = decltype(std::declval<F>()(
^
As pointed out, this would not handle a container of input iterators well. So let's fix it. We need something to determine the size of the container. If the container has a size() member function, we can use that. Otherwise if the iterators do not have category input_iterator_tag (don't know of any other way to distinguish input iterators...), we can use that. Otherwise, we're kind of out of luck. A good way of doing decreasing order of preference like this is to introduce a chooser hierarchy:
namespace details {
template <int I> struct chooser : chooser<I-1> { };
template <> struct chooser<0> { };
}
And then just walk down:
namespace details {
template <typename C>
auto size(C& container, chooser<2>) -> decltype(container.size(), void())
{
return container.size();
}
template <typename C,
typename It = decltype(adl_begin(std::declval<C&>()))
>
auto size(C& container, chooser<1>)
-> std::enable_if_t<
!std::is_same<std::input_iterator_tag,
typename std::iterator_traits<It>::iterator_category
>::value,
size_t>
{
return std::distance(adl_begin(container), adl_end(container));
}
template <typename C>
size_t size(C& container, chooser<0>)
{
return 1; // well, we have no idea
}
}
template <typename C>
size_t size(C& container)
{
return size(container, details::chooser<10>{});
}
Then we can use size() to reserve() our vector to the best of our ability:
template <typename C,
typename F,
typename E = std::decay_t<decltype(std::declval<F>()(
*adl_begin(std::declval<C>())
))>
>
std::vector<E> apply(C&& container, F&& func)
{
std::vector<E> result;
result.reserve(size(container));
for (auto&& elem : container) {
result.push_back(std::forward<F>(func)(std::forward<decltype(elem)>(elem)));
}
return result;
}

This can certainly be done and would probably look something like this:
template <class Container, class Function>
auto apply (const Container &cont, Function fun) {
std::vector< typename
std::result_of<Function(const typename Container::value_type&)>::type> ret;
ret.reserve(cont.size());
for (const auto &v : cont) {
ret.push_back(fun(v));
}
return ret;
}
If you want to be super general and handle C arrays and everything, you might need to add a couple of overloads for the special cases.
Live example

This has already been discussed in comments, but I think it should also be given as an answer:
The function std::transform from <algorithm> does what you want.
The following code works for me:
#include <vector>
#include <algorithm>
using namespace std;
//...
vector<int> input({1,2,3});
transform(input.begin(), input.end(), input.begin(), [](int num){return num*num;});

This works with your example, and with most of the containers. I use std::transform, because it can be optimized for each stl iterator. I started out from Baum mit Augen's answer, which was deleted later.
template<typename Container, typename Function>
using _mapT = std::vector<typename std::result_of<Function(const typename Container::value_type&)>::type>;
template <typename Container, typename Function>
_mapT<Container, Function> map(const Container &container, Function &&f)
{
_mapT<Container, Function> ret; ret.reserve(container.size());
std::transform(container.begin(), container.end(), std::back_inserter(ret), std::forward<Function>(f));
return ret;
}

Related

Canonical C++ way to control function return type with sensible default

What is the canonical way to control the return type of a function based on an input type with a sensible default?
e.g.
// by default want R = decltype(container)::value_type
template<typename R>
R func(const auto& container)
{
R result{};
// some calculations using container
return result;
}
The usage would be:
std::vector<int> ct{};
func(ct); // default result -> int
func<double>(ct); // custom call -> double
I could drop the use of auto and use another template argument:
template<typename C, typename R = C::value_type>
R func(const C& container)
{
R result{};
// some calculations using container
return result;
}
But then usage for the control case is less than ideal:
func<std::vector<int>, double>(ct); // custom call -> double
I could reorder the template arguments:
template<typename R, typename C>
R func(const C& container)
{
R result{};
// some calculations using container
return result;
}
But then I lose my default behaviour:
func(ct); // no longer works
func<int>(ct); // required <int>
I don't know about canonical C++, but this works:
template<typename R=void>
auto func(const auto& container)
{
using Out = std::conditional_t<
std::is_same_v<R, void>,
typename std::decay_t<decltype(container)>::value_type,
R>;
Out result{};
// some calculations using container
return result;
}
godbolt
You can combine function template overloading with SFINAE to handle both cases:
template<typename C, typename R = typename C::value_type>
R func(C const& container) {
R result{};
// some calculations using container
return result;
}
template<typename R, typename C>
R func(C const& container) {
return func<C, R>(container);
}
godbolt
You could work around the problem by using auto as the return type. Something like
// by default want R = decltype(container)::value_type
template<typename R = void>
auto func(const auto& container)
{
// if R is void use value_type otherwise use R
using RetType = std::conditional_t<std::is_same_v<R, void>, typename std::remove_cvref_t<decltype(container)>::value_type, R>;
RetType result{};
// some calculations using container
return result;
}
If you always want to return something you can use void as sentinel and defer deduction of the return type to the body of the function:
#include <type_traits>
template <typename T,typename Select>
struct select_default_or_T{
using type = std::conditional_t< std::is_same_v<void,Select> , typename T::value_type,Select>::type;
};
template<typename R = void>
auto func(const auto& container)
{
using R = typename select_default_or_T<decltype(container),R>::type;
R result{};
// some calculations using container
return result;
}
Well, the name of the traits needs a fix, but I think you get the idea.

Call each tuple member with a result of the previous call recursively

Lets say I have a tuple
std::tuple<Operation<1>, Operation<2>, Operation<3>>. Operation<> has a member function with the signature SomeType someFunction(SomeType). What I want to do is to call the operations successively such that the resulting order of calls would be Operation<3>::someFunction(Operation<2>::someFunction(Operation<1>::someFunction())) and I would get the final SomeType value. How do I achieve this using variadic templates (I have access to C++17)?
I can call each member function with std::apply([](auto& ...x) { (..., x.someFunction()); }, tuple); but what kind of expression do I need to call someFunction() with the output of the previous call?
I suppose you can combine std::apply() and template folding with a lambda as follows
auto l = [&val](auto ... Ops)
{ ((val = Ops.someFunc(val)), ...); };
The following is a full working example
#include <tuple>
#include <iostream>
template <int I>
struct Oper
{
static constexpr int someFunc (int i)
{ return i + I; }
};
int main ()
{
std::tuple<Oper<1>, Oper<2>, Oper<3>, Oper<4>> t;
int val {}; // starting value
auto l = [&val](auto ... Ops)
{ ((val = Ops.someFunc(val)), ...); };
std::apply(l, t);
std::cout << val << std::endl;
}
#max66's solution is elegant and concise, however one caveat is that all your operations must handle and return the same type (which is your case), I will try to propose a broader approach.
The idea is to rely on an overloaded operator>> to apply the desired operation on a state and the next step. To do so let's first define some building blocks:
// Just to avoid the hassle of std::forwarding by hand everywhere
#define CPPFWD(x) std::forward<decltype(x)>(x)
// We do not want to pollute the global namespace with our special operator>>
namespace combine {
// This will make the appropriate functor for each step
template <typename T, typename Op>
auto make_operation(T&& tuple_element, Op&& op) {
return [ el = CPPFWD(tuple_element),
op = CPPFWD(op) ](auto&& input) mutable {
return op(el, CPPFWD(input));
};
}
template <typename Input, typename Op>
auto operator>>(Input&& input, Op&& op) {
return CPPFWD(op)(CPPFWD(input));
}
} // ns combine
Now we are ready to tackle the left fold implementation:
template <typename State, typename Tuple, typename Op, size_t... Is>
auto fold_left_impl(State&& state, Tuple&& tuple, Op&& op, std::index_sequence<Is...>) {
using combine::make_operation;
// We want our operator>> to be in the immediate scope here
// to avoid selecting an inappropriate hypothetical overload
using combine::operator>>;
using std::get;
return (CPPFWD(state) >> ... >> make_operation(get<Is>(CPPFWD(tuple)), op));
}
Finally the function exposed to the end-user:
template <typename T>
using remove_cvref_t = std::remove_cv_t< std::remove_reference_t< T > >;
template <typename State, typename Tuple, typename Op>
auto fold_left(State&& state, Tuple&& tuple, Op&& op) {
return fold_left_impl(
CPPFWD(state),
CPPFWD(tuple),
CPPFWD(op),
std::make_index_sequence< std::tuple_size< remove_cvref_t< Tuple > >::value > {} );
}
In your case, the correct usage would be:
std::tuple<Operation<1>, Operation<2>, Operation<3>> t;
fold_left(
0,
t,
[](auto&& op, auto&& in) {
return CPPFWD(op).someFunc(CPPFWD(in));
} );
A live example can be found on Coliru

Compiler does not deduce template parameters (map std::vector -> std::vector)

I have the following template.
template<typename T, typename U>
std::vector<U> map(const std::vector<T> &v, std::function<U(const T&)> f) {
std::vector<U> res;
res.reserve(v.size());
std::transform(std::begin(v), std::end(v), std::end(res), f);
return res;
}
When I use it in my code I have the specify the template parameters. Why is the compiler not able to deduce this for me? How do I have to change my template definition to make this work?
vector<int> numbers = { 1, 3, 5 };
// vector<string> strings = map(numbers, [] (int x) { return string(x,'X'); });
vector<string> strings = map<int, string>(numbers, [] (int x) { return string(x,'X'); });
Runnable code: http://ideone.com/FjGnxd
The original code in this question comes from here: The std::transform-like function that returns transformed container
Your function expects an std::function argument, but you're calling it with a lambda expression instead. The two are not the same type. A lambda is convertible to std::function, but template argument deduction requires exact matches and user defined conversions are not considered. Hence the deduction failure.
Deduction does work if you actually pass an std::function to map().
std::function<string(int const&)> fn = [] (int x) { return string(x,'X'); };
vector<string> strings = map(numbers, fn);
Live demo
One possible workaround to avoid having to specify the template arguments is to modify the function to accept any kind of callable, rather than an std::function object.
template<typename T, typename Func>
std::vector<typename std::result_of<Func(T)>::type>
map(const std::vector<T> &v, Func f) {
// ...
}
Another version of the same idea, using decltype and declval instead of result_of
template<typename T, typename Func>
std::vector<decltype(std::declval<Func>()(std::declval<T>()))>
map(const std::vector<T> &v, Func f) {
// ...
}
Finally, using a trailing return type
template<typename T, typename Func>
auto map(const std::vector<T> &v, Func f)
-> std::vector<decltype(f(v[0]))> {
// ...
}
Live demo

void_t "can implement concepts"?

I was watching the second part of Walter Brown's CppCon2014 talk on template metaprogramming, during which he discussed the uses of his novel void_t<> construction. During his presentation Peter Sommerlad asked him a question that I didn't quite understand. (link goes directly to the question, the code under discussion took place directly before that)
Sommerlad asked
Walter, would that mean we actually can implement concepts lite right now?
to which Walter responded
Oh yeah! I've done it ... It doesn't have quite the same syntax.
I understood this exchange to be about Concepts Lite. Is this pattern really that versatile? For whatever reason, I am not seeing it. Can someone explain (or sketch) how something like this might look? Is this just about enable_if and defining traits, or what was the questioner referring to?
The void_t template is defined as follows:
template<class ...> using void_t = void;
He uses this then to detect if type statements are well formed, using this to implement the is_copy_assignable type trait:
//helper type
template<class T>
using copy_assignment_t
= decltype(declval<T&>() = declval<T const&>());
//base case template
template<class T, class=void>
struct is_copy_assignable : std::false_type {};
//SFINAE version only for types where copy_assignment_t<T> is well-formed.
template<class T>
struct is_copy_assignable<T, void_t<copy_assignment_t<T>>>
: std::is_same<copy_assignment_t<T>,T&> {};
Because of the talk, I understand how this example works, but I don't see how we get from here to something like Concepts Lite.
Yes, concepts lite basically dresses up SFINAE. Plus it allows deeper introspection to allow for better overloading. However that only works if the concept predicates are defined as concept bool. The improved overloading does not work with the current concept predicates, but conditional overloading can be used. Lets look how we can define predicates, constrain templates, and overload functions in C++14. This is kind of long, but it goes over how to create all of the tools needed to accomplish this in C++14.
Defining Predicates
First, it is kind of ugly to read the predicate with all the std::declval and decltype everywhere. Instead, we can take advantage of the fact that we can constrain a function using a trailing decltype(from Eric Niebler’s blog post here), like this:
struct Incrementable
{
template<class T>
auto requires_(T&& x) -> decltype(++x);
};
So if ++x is not valid, then the requires_ member function is not callable. So we can create a models trait that just checks if requires_ is callable using void_t:
template<class Concept, class Enable=void>
struct models
: std::false_type
{};
template<class Concept, class... Ts>
struct models<Concept(Ts...), void_t<
decltype(std::declval<Concept>().requires_(std::declval<Ts>()...))
>>
: std::true_type
{};
Constraining Templates
So when we want to constrain the template based on the concept, we will still need to use enable_if, but we can use this macro to help make it cleaner:
#define REQUIRES(...) typename std::enable_if<(__VA_ARGS__), int>::type = 0
So we can define an increment function that is constrained based on Incrementable concept:
template<class T, REQUIRES(models<Incrementable(T)>())>
void increment(T& x)
{
++x;
}
So if we call increment with something that is not Incrementable, we will get an error like this:
test.cpp:23:5: error: no matching function for call to 'incrementable'
incrementable(f);
^~~~~~~~~~~~~
test.cpp:11:19: note: candidate template ignored: disabled by 'enable_if' [with T = foo]
template<class T, REQUIRES(models<Incrementable(T)>())>
^
Overloading Functions
Now if we want to do overloading, we want to use conditional overloading. Say we want to create an std::advance using concept predicates, we could define it like this(for now we will ignore the decrementable case):
struct Incrementable
{
template<class T>
auto requires_(T&& x) -> decltype(++x);
};
struct Advanceable
{
template<class T, class I>
auto requires_(T&& x, I&& i) -> decltype(x += i);
};
template<class Iterator, REQUIRES(models<Advanceable(Iterator, int)>())>
void advance(Iterator& it, int n)
{
it += n;
}
template<class Iterator, REQUIRES(models<Incrementable(Iterator)>())>
void advance(Iterator& it, int n)
{
while (n--) ++it;
}
However, this causes an ambiguous overload(In concepts lite this would still be an ambiguous overload unless we change our predicates to refer to the other predicates in a concept bool) when its used with std::vector iterator. What we want to do is order the calls, which we can do using conditional overloading. It can be thought of writing something like this(which is not valid C++):
template<class Iterator>
void advance(Iterator& it, int n) if (models<Advanceable(Iterator, int)>())
{
it += n;
}
else if (models<Incrementable(Iterator)>())
{
while (n--) ++it;
}
So if the first function isn't called, it will call the next function. So lets start by implementing it for two functions. We will create a class called basic_conditional which accepts two function objects as template parameters:
struct Callable
{
template<class F, class... Ts>
auto requires_(F&& f, Ts&&... xs) -> decltype(
f(std::forward<Ts>(xs)...)
);
};
template<class F1, class F2>
struct basic_conditional
{
// We don't need to use a requires clause here because the trailing
// `decltype` will constrain the template for us.
template<class... Ts>
auto operator()(Ts&&... xs) -> decltype(F1()(std::forward<Ts>(xs)...))
{
return F1()(std::forward<Ts>(xs)...);
}
// Here we add a requires clause to make this function callable only if
// `F1` is not callable.
template<class... Ts, REQUIRES(!models<Callable(F1, Ts&&...)>())>
auto operator()(Ts&&... xs) -> decltype(F2()(std::forward<Ts>(xs)...))
{
return F2()(std::forward<Ts>(xs)...);
}
};
So now that means we need to define our functions as functions objects instead:
struct advance_advanceable
{
template<class Iterator, REQUIRES(models<Advanceable(Iterator, int)>())>
void operator()(Iterator& it, int n) const
{
it += n;
}
};
struct advance_incrementable
{
template<class Iterator, REQUIRES(models<Incrementable(Iterator)>())>
void operator()(Iterator& it, int n) const
{
while (n--) ++it;
}
};
static conditional<advance_advanceable, advance_incrementable> advance = {};
So now if we try to use it with an std::vector:
std::vector<int> v = { 1, 2, 3, 4, 5, 6 };
auto iterator = v.begin();
advance(iterator, 4);
std::cout << *iterator << std::endl;
It will compile and print out 5.
However, std::advance actually has three overloads, so we can use the basic_conditional to implement conditional that works for any number of functions using recursion:
template<class F, class... Fs>
struct conditional : basic_conditional<F, conditional<Fs...>>
{};
template<class F>
struct conditional<F> : F
{};
So, now we can write the full std::advance like this:
struct Incrementable
{
template<class T>
auto requires_(T&& x) -> decltype(++x);
};
struct Decrementable
{
template<class T>
auto requires_(T&& x) -> decltype(--x);
};
struct Advanceable
{
template<class T, class I>
auto requires_(T&& x, I&& i) -> decltype(x += i);
};
struct advance_advanceable
{
template<class Iterator, REQUIRES(models<Advanceable(Iterator, int)>())>
void operator()(Iterator& it, int n) const
{
it += n;
}
};
struct advance_decrementable
{
template<class Iterator, REQUIRES(models<Decrementable(Iterator)>())>
void operator()(Iterator& it, int n) const
{
if (n > 0) while (n--) ++it;
else
{
n *= -1;
while (n--) --it;
}
}
};
struct advance_incrementable
{
template<class Iterator, REQUIRES(models<Incrementable(Iterator)>())>
void operator()(Iterator& it, int n) const
{
while (n--) ++it;
}
};
static conditional<advance_advanceable, advance_decrementable, advance_incrementable> advance = {};
Overloading With Lambdas
However, additionally, we could use lambdas to write it instead of function objects which can help make it cleaner to write. So we use this STATIC_LAMBDA macro to construct lambdas at compile time:
struct wrapper_factor
{
template<class F>
constexpr wrapper<F> operator += (F*)
{
return {};
}
};
struct addr_add
{
template<class T>
friend typename std::remove_reference<T>::type *operator+(addr_add, T &&t)
{
return &t;
}
};
#define STATIC_LAMBDA wrapper_factor() += true ? nullptr : addr_add() + []
And add a make_conditional function that is constexpr:
template<class... Fs>
constexpr conditional<Fs...> make_conditional(Fs...)
{
return {};
}
Then we can now write the advance function like this:
constexpr const advance = make_conditional(
STATIC_LAMBDA(auto& it, int n, REQUIRES(models<Advanceable(decltype(it), int)>()))
{
it += n;
},
STATIC_LAMBDA(auto& it, int n, REQUIRES(models<Decrementable(decltype(it))>()))
{
if (n > 0) while (n--) ++it;
else
{
n *= -1;
while (n--) --it;
}
},
STATIC_LAMBDA(auto& it, int n, REQUIRES(models<Incrementable(decltype(it))>()))
{
while (n--) ++it;
}
);
Which is little more compact and readable than using the function object versions.
Additionally, we could define a modeled function to reduce down the decltype ugliness:
template<class Concept, class... Ts>
constexpr auto modeled(Ts&&...)
{
return models<Concept(Ts...)>();
}
constexpr const advance = make_conditional(
STATIC_LAMBDA(auto& it, int n, REQUIRES(modeled<Advanceable>(it, n)))
{
it += n;
},
STATIC_LAMBDA(auto& it, int n, REQUIRES(modeled<Decrementable>(it)))
{
if (n > 0) while (n--) ++it;
else
{
n *= -1;
while (n--) --it;
}
},
STATIC_LAMBDA(auto& it, int n, REQUIRES(modeled<Incrementable>(it)))
{
while (n--) ++it;
}
);
Finally, if you are interested in using existing library solutions(rather than rolling your own like I've shown). There is the Tick library that provides a framework for defining concepts and constraining templates. And the Fit library can handle the functions and overloading.

Constraints on template types

Suppose, I want to implement a generic higher-order Map function in C++. Map should take a container and a transformation function and return a container of the same type, but possibly with different type of items.
Let's take vector for instance:
template <typename InT, typename OutT, typename Tr>
vector<OutT> Map(vector<InT> cont, Tr tr)
{
OutCont out(cont.size());
auto oit = out.begin();
for (auto it = cont.cbegin(); it != cont.cend(); ++it, ++ot)
{
*oit = tr(*it);
}
}
which I want to use like this:
vector<int> v(10);
std::iota(v.begin(), v.end(), 0);
auto x = Map(v, [](int x) -> int {return x * 2;});
This fails in VC++ 2012, giving me the following error:
error C2783: 'std::vector<OutT> Map(std::vector<_Ty>,Tr)' : could not deduce template argument for 'OutT'
It seems to me that the compiler has all the necessary information, because I explicitly defined the return type in the lambda. Is there a way around this?
The above example uses vector. Is there a way to use a generic type, so that the input and output types are the same? For instance if I have an input container defined as vector<string> and the transformation function tr(string a) -> int, then my goal is to make the compiler to figure out the output type to be vector<int>. Here's the pseudo-code for what I want to achieve:
template <typename Cont<InT>, typename Cont<OutT>, typename Tr<InT, OutT>>
Cont<OutT> Map(Cont<InT> cont, Tr<InT, OutT> tr)
{
// Implementation
}
You may write something like:
template <typename InT, typename Tr>
auto Map(std::vector<InT> cont, Tr tr) -> std::vector<decltype(tr(cont[0]))>
{
std::vector<decltype(tr(cont[0]))> out(cont.size());
auto oit = out.begin();
for (auto it = cont.cbegin(); it != cont.cend(); ++it, ++oit)
{
*oit = tr(*it);
}
return out;
}
Out type is deduced.
[Edit]
For a more generic function with more container:
template <template<typename, typename...> class Container, typename InT, typename Tr, typename... Args>
auto Map(const Container<InT, Args...>& cont, Tr tr) -> Container<decltype(tr(cont[0])), Args...>
{
Container<decltype(tr(cont[0])), Args...> out(cont.size());
auto oit = out.begin();
for (auto it = cont.cbegin(); it != cont.cend(); ++it, ++oit)
{
*oit = tr(*it);
}
return out;
}
Notice the typename... needed because std::vector can also take allocator