In C++03 the following code works fine:
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
std::vector<int> v2;
v2.push_back(2);
v2.push_back(3);
v2.push_back(4);
std::transform(v.begin(), v.end(), v2.begin(), v2.begin(), std::max<int>);
return 0;
}
In C++11 this doesn't work because it added an overload for std::max that contains an initializer_list. Therefore, you have to use a very ugly cast to choose the correct overload:
static_cast<const int& (*)(const int&, const int&)>(std::max)
I have a few questions.
Why did the standard committee decide to do this knowing it would (probably) break existing code and force the user to create an ugly cast?
Are future standards of C++ going to attempt to alleviate this problem?
What is a workaround?
If you are doing this sufficiently frequently, you might want to write a transparent functor wrapper:
struct my_max {
template<class T>
const T& operator()(const T& a, const T& b) const{
return std::max(a, b);
}
};
Then you can simply do
std::transform(v.begin(), v.end(), v2.begin(), v2.begin(), my_max());
whenever you need it, rather than writing a lambda or a cast each time. This is basically the same idea as the transparent operator functors - let the template arguments be deduced at the actual call site rather than explicitly specified when you create the functor.
If you want to make this fancier, you can even have operator() take heterogeneous types and add perfect forwarding and use trailing return types:
struct my_max {
template<class T, class U>
constexpr auto operator()( T&& t, U&& u ) const
-> decltype(t < u ? std::forward<U>(u) : std::forward<T>(t)){
return t < u ? std::forward<U>(u) : std::forward<T>(t);
}
};
In C++14, this is simplified to
struct my_max {
template<class T, class U>
constexpr decltype(auto) operator()( T&& t, U&& u ) const{
return t < u ? std::forward<U>(u) : std::forward<T>(t);
}
};
What is a workaround?
A lambda is probably the most readable and useful for predicates and comparators:
std::transform(v.begin(), v.end(), v2.begin(), v2.begin(),
[] (int a, int b) {return std::max(a,b);} );
You might want to check out T.C.s functor if you need it more often. Or, with C++14:
auto max = [] (auto&& a, auto&& b) -> decltype(auto)
{return a > b? std::forward<decltype(a)>(a) : std::forward<decltype(b)>(b);};
Why did the standard committee decide to do this knowing it would
(probably) break existing code and force the user to create an ugly
cast?
The only explanation is that they found the new overload to bring enough joy to compensate the breaking of existing code and the need for workarounds in future.
You could just use std::max_element instead of this new overload, so you trade the syntax sugar for passing std::max-specializations as predicates for the syntax sugar of finding the maximum element within a couple of variables without explicitly creating an array for it.
Basically
std::transform( ..., std::max<int> );
// <=>
std::transform( ..., [] (int a, int b) {return std::max(a,b);} );
vs
int arr[] {a,b,c,d}; // You don't have an array with a,b,c,d included consecutively yet
int maximum = *std::max_element( std::begin(arr), std::end(arr) ); // ensure arr non-empty!
// <=>
auto maximum = std::max({a, b, c, d});
Maybe it does compensate? On the other hand, you barely ever need the latter.
Are future standards of C++ going to attempt to alleviate this
problem?
I don't think so. Apparently, the standard committee really doesn't like to remove recently introduced features. I don't really see that much of a problem either; The lambda does the job.
Although I've accepted T.C's answer which provides a comprehensive breakdown, as stated in a comment, I want to mimic the transparent comparator functor for class templates like std::less. This answer is provided for critique by others incase there's anything wrong with the syntax.
template <typename T = void>
struct my_max;
template <>
struct my_max<void> {
template<class T, class U>
constexpr decltype(auto) operator()( T&& t, U&& u ) const {
return t < u ? std::forward<U>(u) : std::forward<T>(t);
}
};
If you are ok with using C++20 ranges additions you can just use std::ranges::max.
std::ranges::max is not a function, but a struct so it can be passed to the algorithms.
Example:
#include <iostream>
#include <algorithm>
#include <vector>
#include <fmt/ranges.h>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
std::vector<int> v2;
v2.push_back(2);
v2.push_back(3);
v2.push_back(4);
std::transform(v.begin(), v.end(), v2.begin(), v2.begin(), std::ranges::max);
std::cout << fmt::format("{}", v2);
}
If you have recent boost you can use BOOST_HOF_LIFT macro.
fmt lib in example is just for printing vector, all you need is boost
#include <type_traits>
#include <cassert>
#include <iostream>
#include <algorithm>
#include <vector>
#include <boost/hof/lift.hpp>
#include <fmt/ranges.h>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
std::vector<int> v2;
v2.push_back(2);
v2.push_back(3);
v2.push_back(4);
std::transform(v.begin(), v.end(), v2.begin(), v2.begin(), BOOST_HOF_LIFT(std::max<int>));
std::cout << fmt::format("{}", v2);
}
Related
In the simple parser library I am writing, the results of multiple parsers is combined using std::tuple_cat. But when applying a parser that returns the same result multiple times, it becomes important to transform this tuple into a container like a vector or a deque.
How can this be done? How can any tuple of the kind std::tuple<A>, std::tuple<A, A>, std::tuple<A, A, A> etc be converted into a std::vector<A>?
I think this might be possible using typename ...As and sizeof ...(As), but I am not sure how to create a smaller tuple to call the function recursively. Or how to write an iterative solution that extracts elements from the tuple one by one. (as std::get<n>(tuple) is constructed at compile-time).
How to do this?
With the introduction of std::apply(), this is very straightforward:
template <class Tuple,
class T = std::decay_t<std::tuple_element_t<0, std::decay_t<Tuple>>>>
std::vector<T> to_vector(Tuple&& tuple)
{
return std::apply([](auto&&... elems){
return std::vector<T>{std::forward<decltype(elems)>(elems)...};
}, std::forward<Tuple>(tuple));
}
std::apply() is a C++17 function but is implementable in C++14 (see link for possible implementation). As an improvement, you could add either SFINAE or a static_assert that all the types in the Tuple are actually T.
As T.C. points out, this incurs an extra copy of every element, since std::initializer_list is backed by a const array. That's unfortunate. We win some on not having to do boundary checks on every element, but lose some on the copying. The copying ends up being too expensive, an alternative implementation would be:
template <class Tuple,
class T = std::decay_t<std::tuple_element_t<0, std::decay_t<Tuple>>>>
std::vector<T> to_vector(Tuple&& tuple)
{
return std::apply([](auto&&... elems) {
using expander = int[];
std::vector<T> result;
result.reserve(sizeof...(elems));
expander{(void(
result.push_back(std::forward<decltype(elems)>(elems))
), 0)...};
return result;
}, std::forward<Tuple>(tuple));
}
See this answer for an explanation of the expander trick. Note that I dropped the leading 0 since we know the pack is non-empty. With C++17, this becomes cleaner with a fold-expression:
return std::apply([](auto&&... elems) {
std::vector<T> result;
result.reserve(sizeof...(elems));
(result.push_back(std::forward<decltype(elems)>(elems)), ...);
return result;
}, std::forward<Tuple>(tuple));
Although still relatively not as nice as the initializer_list constructor. Unfortunate.
Here's one way to do it:
#include <tuple>
#include <algorithm>
#include <vector>
#include <iostream>
template<typename first_type, typename tuple_type, size_t ...index>
auto to_vector_helper(const tuple_type &t, std::index_sequence<index...>)
{
return std::vector<first_type>{
std::get<index>(t)...
};
}
template<typename first_type, typename ...others>
auto to_vector(const std::tuple<first_type, others...> &t)
{
typedef typename std::remove_reference<decltype(t)>::type tuple_type;
constexpr auto s =
std::tuple_size<tuple_type>::value;
return to_vector_helper<first_type, tuple_type>
(t, std::make_index_sequence<s>{});
}
int main()
{
std::tuple<int, int> t{2,3};
std::vector<int> v=to_vector(t);
std::cout << v[0] << ' ' << v[1] << ' ' << v.size() << std::endl;
return 0;
}
Although, this doesn't answer the question completely, This still might be suitable in some cases. Only when the number of elements in tuple is around 5, 6. (And you know the size).
tuple<int, int, int, int> a = make_tuple(1, 2, 3, 4);
auto [p, q, r, s] = a;
vector<int> arr(p, q, r, s); // Now, arr has the same elements as in tuple a
Note that, this is C++ 17 feature. More info here
I encountered this problem when using std::cref. A minimal example looks like this:
template<typename Fn, typename T>
auto apply(Fn f, const T &t) -> decltype(f(t))
{
return f(t);
}
int n = 123;
apply(std::cref<int>, n); // <- compile error: can't infer type `Fn`
apply([](const int &x) { return std::cref(x); }, n); // ok
I think the problem with the first example is that std::cref<T> has two overloaded versions, one accepting a const T & and the other accepting a std::reference_wrapper<const T>. Is it possible to instantiate a specific version in my case?
Your apply function seems kind of redundant in this case. Why not cut the middleman?
#include <vector>
#include <algorithm>
#include <iterator>
#include <functional>
int main() {
std::vector<int> v(10);
std::vector<std::reference_wrapper<const int>> v2;
std::transform(v.begin(), v.end(), std::back_inserter(v2),
static_cast<std::reference_wrapper<const int>(*)(const int&)>(&std::cref<int>));
}
THe problem is that cref has several forms. So when you write cref<int> it is not yet clear which of the following you mean:
reference_wrapper<const int> cref (const int& elem)
reference_wrapper<const int> cref (reference_wrapper<int>& x)
The lambda version doesn't have this ambiguity. By the way, it's a good idea to get accustomed to it ;-)
Now if the readability is really an issue, nothing prevents you from doing this:
auto take_ref = [](const int &x) { return std::cref(x); };
apply(take_ref, n); // compile fine
My question is simple, see example:
std::array<int,6> a = {{0,1,2,3,4,5}}; // -- given container.
auto F = []( int i ) { return i*i; }; // -- given function.
std::vector<int> v; // need create
// my solution:
v.reserve( a.size () );
for( std::size_t i = 0; i < a.size(); ++i )
v.push_back( F(a[i]) );
// but I need something like
std::vector<int>v( a.begin(), a.end(), <|applying each element to F|> );
Can I create container something like above not calling reserve explicitly and any reallocation?
EDIT:
I want avoid reserve; because othercase my first solution is good
for me :)
I want avoid any resize; because it's initialzed each
element by default ctor.
I will use this in the real project which may included many 3-rd party libraries ( boost, Soft-STL, ...).
The standard algorithm std::transform does exactly this!
std::vector<int> v(a.size());
std::transform(
std::begin(a), std::end(a),
std::begin(v),
F
);
You can start with an empty vector and use std::back_inserter, if you like:
std::vector<int> v;
std::transform(
std::begin(a), std::end(a),
std::back_inserter(v),
F
);
But you're subjecting yourself to needless re-allocations if you do that (unless you reserve first, as in your original attempt). You can decide for yourself what your priority is.
Use std::transform:
#include <algorithm> // std::transform
#include <iterator> // std::back_inserter
....
transform(a.begin(), a.end(), back_inserter(v), F);
You may want to call v.reserve(asize()) first to avoid re-allocations.
Another solution is to use boost::transform_iterator. The benefit is that you can pass iterators to the container constructor. That avoids memory reallocations compared to when using std::back_inserter or having to call reserve or resize on the destination. All in one statement:
std::vector<int> result(
boost::make_transform_iterator(std::begin(a), F)
, boost::make_transform_iterator(std::end(a), F)
);
You can achieve terser syntax though, like this:
std::vector<int> result(transform_range(a, F));
transform_range implementation:
template<class Iterator>
struct AutoSequence
{
Iterator const beg_, end_;
template<class T>
operator std::vector<T>() const {
return {beg_, end_};
}
};
template<class Function, class InSeq>
auto transform_range(InSeq const& in) -> AutoSequence<decltype(boost::make_transform_iterator<Function>(in.begin()))> {
return {
boost::make_transform_iterator<Function>(std::begin(in))
, boost::make_transform_iterator<Function>(std::end(in))
};
}
template<class Function, class InSeq>
auto transform_range(InSeq const& in, Function&& f) -> AutoSequence<decltype(boost::make_transform_iterator(in.begin(), f))> {
return {
boost::make_transform_iterator(std::begin(in), f)
, boost::make_transform_iterator(std::end(in), f)
};
}
The boost function make_function_output_iterator converts a function that would be appropriate for std::for_each into an iterator appropriate for std::copy. Is there a boost function that does the reverse. That is, takes an iterator appropriate for std::copy and converts it to a function appropriate for std::for_each.
So if I have an output iterator output_iter. I need
for_each(v1.begin(), v1.end(), make_output_iterator_function(output_iter));
To do the same thing as
copy(v1.begin(), v1.end(), output_iter);
Maybe std::insert_iterator or std::transform are what you are looking for?
You can bind std::insert_iterator::operator=, which does an insert on every invocation, with some boost::bind sorcery:
#include <boost/bind.hpp>
#include <vector>
#include <iterator>
#include <algorithm>
typedef std::vector<int> Container;
typedef std::insert_iterator< Container > InsertIt;
int main(){
Container v1, v2;
InsertIt insert_it (v2,v2.end());
std::for_each(v1.begin(), v1.end(),
boost::bind(static_cast<InsertIt& (InsertIt::*)(typename Container::const_reference)>(&InsertIt::operator=), insert_it, _1));
}
If you have the option I'd do this with lambdas rather than std/boost::bind, e.g.:
std::vector<type> v1;
std::for_each(v1.begin(), v1.end() [&output_iter](const type& t) {*output_iter++ = t});
Of course it would make more sense to just use std::copy in the first place!
The class
template<typename T>
struct iterator_to_function {
T iter_;
iterator_to_function(const T& iter) : iter_(iter) {}
template<typename T2>
T& operator()(const T2& elem) {*iter_=elem; return ++iter_;}
};
template<class T>
iterator_to_function<T> make_iterator_function(const T& iter)
{
return iterator_to_function<T>(iter);
}
Converts an output iterator to a unary function.
typedef vector<int> t_vec;
t_vec v;
t_vec v2;
for_each(v.begin(), v.end(),
make_iterator_function(back_inserter(v2));
map<T,Z> m= ...;
vector<T> v;
v.reserve(m.size);
for(map<T,Z>::iterator it=m.begin();it!=m.end();++it)
{
v.push_back(it->first);
}
Is there a nicer 1-line version using some STL function(s)?
edit: not using c++11!
Portable:
struct SelectKey {
template <typename F, typename S>
F operator()(const std::pair<const F, S> &x) const { return x.first; }
};
std::transform(m.cbegin(), m.cend(), std::back_inserter(v), SelectKey());
I think some implementations of STL have a non-standard extension called select1st, which is the equivalent of SelectKey shown here. As K-Ballo pointed out in the comments, there's also a TR1 version. I like the explicitly-named version as it's easier to see what's going on.
Since there's no need for state, you can get away with slightly less boilerplate by using an actual function rather than a functor:
template <typename F, typename S>
F SelectKey()(const std::pair<const F, S> &x) { return x.first; }
std::transform(m.cbegin(), m.cend(), std::back_inserter(v), SelectKey);
If you could use C++11, you could use a lambda, which keeps the selection code close to where it's used:
std::transform(m.cbegin(), m.cend(), std::back_inserter(v),
[](const std::pair<const F, S> &x) { return x.first; });
or even range-based for-loop, which is probably the most elegant and readable:
for(const auto &x : m) {
v.push_back(x.first);
}
Pre C++11, you could use transform and a custom function struct:
template <class K, class V>
struct key_selector : std::unary_function<const std::pair<K, V>&, const K&>
{
const K& operator()(const std::pair<K, V>& element) const
{
return element.first;
}
};
transform(m.begin(), m.end(), back_inserter(v), key_selector<T,Z>());
If you have access to boost or TR1, you can replace key_selector with mem_fn
transform(m.begin(), m.end(), back_inserter(v), mem_fn(&map<T,Z>::value_type::first));
Post- C++11, you can use lambdas:
transform(m.begin(), m.end(), back_inserter(v), [](const map<T,Z>::value_type& x) {return x.first;});
In C++11, you can use lambda expressions:
typedef std::map< std::string, std::string > map_t;
map_t map;
std::vector< std::string > v;
std::for_each(map.begin(), map.end(), [&v](map_t::value_type const& it)
{
v.push_back(it.first);
});
You can do something along the lines of:
std::transform(m.begin(), m.end(), std::back_inserter(v), FUNCTOR);
Where FUNCTOR depends on what version of the STL or libraries and compilers that you have.
C++11 (lambda)
std::transform(m.begin(), m.end(), std::back_inserter(v), [](map<T,Z>::const_reference a) { return a.first; });
C++11 (std::get)
std::transform(m.begin(), m.end(), std::back_inserter(v), &std::get<0>);
C++ SGI STL has a functor called select1st which can be used
std::transform(m.begin(), m.end(), std::back_inserter(v), select1st);
C++03 (Not C++11) using a functor object like other people have described.