reduce arguments - c++

My question is that I have two arguments vector<int>& ivec and const int& numb. is there a way to eliminate const int& numb? I just want to do add 10 to all elements in the vector. Also I want to eliminate if part, since it's empty. Thanks in advance. Please do it recursively. My goal it to use as few arguments as possible in a recursive function.
#include <iostream>
#include <vector>
using namespace std;
vector<int> addten(vector<int>& ivec, const int& numb) {
if (numb == 0) {
} else {
ivec[numb - 1] += 10;
addten(ivec, numb - 1);
}
return ivec;
}

Your code feels very odd. The C++y way to do this would be:
std::vector<int> vec; // your vector
// adds 10 in place
std::transform(vec.begin(), vec.end(), vec.begin(),
std::bind(std::plus<int>(), _1, 10));
// adds 10 out-of-place
std::vector<int> result;
std::transform(vec.begin(), vec.end(), std::back_inserter(result),
std::bind(std::plus<int>(), _1, 10));
As you have specifically requested, I've implemented a very poor foldl in C++ that operates only on vector<T> instead of on iterators.
#include <vector>
#include <iostream>
// well, here comes C++ origami
template<typename Start, typename F, typename T>
Start foldl(Start s, F f, const std::vector<T>& v) {
return foldl_impl(s, f, v, 0);
}
template<typename Start, typename F, typename T>
Start foldl_impl(Start s, F f, const std::vector<T>& v,
typename std::vector<T>::size_type t) {
if(t == v.size()) return s;
typename std::vector<T>::size_type t2 = t++;
return foldl_impl(f(s, v[t2]), f, v, t);
}
int main()
{
std::vector<int> vec = {1, 2, 3, 4, 5, 6, 7};
std::vector<int> added =
foldl(std::vector<int>()
, [](std::vector<int>& v, int i) { v.push_back(i+10); return v;}
, vec);
for(auto x : added) {
std::cout << x << std::endl;
}
return 0;
}
Please consider that this is far from good C++ style.

Related

Is there an elegant way to instantiate a boost::array from a std::vector?

Writing an interface, I have to convert instances of std::vector<double> to boost::array<double,N>. Each time, by construction (without bug), I'm sure the vector has the right size.
Here is an example of what I'm currently doing (I have about 100 such functions to write in the interface) :
double foo1(const std::vector<double>& x)
{
assert(x.size() == 4);
boost::array<double,4> x_;
for(std::size_t i = 0; i < 4; ++i)
x_[i] = x[i];
return foo1_(x_);
}
double foo2(const std::vector<double>& x)
{
assert(x.size() == 6);
boost::array<double,6> x_;
for(std::size_t i = 0; i < 6; ++i)
x_[i] = x[i];
return foo2_(x_);
}
Is there a shorter way to do that ?
Note 1: I don't use C++11 for compatibility reasons.
Note 2: I added tag stdarray because it can maybe help even if it's a C++11 tag.
Something like this:
#include <boost/array.hpp>
#include <vector>
#include <boost/range/algorithm.hpp>
#include <iostream>
#include <cassert>
template<size_t Size, class Container>
boost::array<typename Container::value_type, Size> as_array(const Container &cont)
{
assert(cont.size() == Size);
boost::array<typename Container::value_type, Size> result;
boost::range::copy(cont, result.begin());
return result;
}
int main()
{
// this is C++11 initialization, but the rest of code is C++03-complient
std::vector<int> v{1, 2, 3};
boost::array<int, 3> a = as_array<3>(v);
boost::range::copy(a, std::ostream_iterator<int>(std::cout,", "));
}
But keep in mind that such a "translation" from a run-time to a compile-time container might be quite dangerous, as its correctness relies on assert, which is eliminated in release mode.
Write a template function:
template<class T,size_t N>
std::array<T,N> convert( const std::vector<T> & v )
{
//assert(v.size() == N);
std::array<T,N> r;
std::copy( v.begin(), v.end(), r.begin() );
return r;
}
then your functions will become one liners:
double foo1(const std::vector<double>& x)
{
return foo1_( convert<double,4>( x ) );
}
live example
You can template over the number of elements (That's what array<> is doing too). If you order the parameters sensibly, you can specify just the size and have double still deduced
template<std::size_t N, typename T>
boost::array<T, N> from_vector(const std::vector<T> & vec)
{
assert(x.size() == N);
boost::array<T, N> res;
std::copy(vec.begin(), vec.end(), res.begin());
return res;
}
Which gets used
double foo1(const std::vector<double> & vec)
{
return foo1_(from_vector<4>(vec));
}
double foo2(const std::vector<double> & vec)
{
return foo2_(from_vector<6>(vec));
}
But a better idea would be to re-implement foo1_ and foo2_ in terms of iterators (or something like gsl::span). You can assert(std::distance(begin, end) == 4) as needed

How to capture variable inside lambda

I have code from here:
std::sort(begin(v), end(v), [](auto const &t1, auto const &t2) {
return get<0>(t1) < get<0>(t2); // or use a custom compare function
});
I wanted to sort tuple multiple times so I wrote this code:
int k = 10;
while(k--){
std::sort(begin(v), end(v), [](auto const &t1, auto const &t2) {
return get<k>(t1) < get<k>(t2); // or use a custom compare function
});
}
but I get error error: ‘k’ is not captured. I tried to do it in this way:
int k = 10;
while(k--){
std::sort(begin(v), end(v), [&k](auto const &t1, auto const &t2) {
return get<k>(t1) < get<k>(t2); // or use a custom compare function
});
}
but it is not the proper way and error error: the value of ‘k’ is not usable in a constant expression occurs.
How to capture k variable?
As mch said in the comment, the problem is that k is not a compile time constant.
For a compile time constant, to iterate from N to 0, you may need template and recursion:
#include <algorithm>
#include <tuple>
#include <type_traits>
#include <vector>
using namespace std; // just for simplify, and not recommended in practice
template <size_t N, typename Iterator, enable_if_t<N == 0, int> = 0>
void foo(Iterator begin, Iterator end)
{
sort(begin, end,
[](const auto &t1, const auto &t2) {
return get<0>(t1) < get<0>(t2);
}
);
}
template <size_t N, typename Iterator, enable_if_t<N != 0, int> = 0>
void foo(Iterator begin, Iterator end)
{
sort(begin, end,
[](const auto &t1, const auto &t2) {
return get<N>(t1) < get<N>(t2);
}
);
foo<N - 1>(begin, end);
}
int main()
{
vector<tuple<int, int>> v{{0, 1}, {0, 0}, {1, 1}};
foo<1>(v.begin(), v.end());
// posible results:
// {0, 0}, {0, 1}, {1, 1}
// {0, 1}, {0, 0}, {1, 1} // impossible if use std::stable_sort instead
}
std::get only accepts a template argument which is an expression whose value that can be evaluated at compiling time.
You can't use k, because it is a variable that changes value.
std::sort(begin(v), end(v), [](auto const &t1, auto const &t2) {
const int k = 3;
return std::get<k>(t1) < std::get<k>(t2); // or use a custom compare function
});
As I wrote in the comments, I know const int = 3 will shadow the k value outside of the lambda expression, but this example shows that get will work when it it receives a compiling time constant value.
For example, if you try to set k = 5, for example where v only has 4 tuple parameters, the compiler will give an error because it knows that this is out of range.
The following code will give an error, but if k is set to 3, it will work
std::vector<std::tuple<int, int, int, int>> v;
std::sort(begin(v), end(v), [](auto const &t1, auto const &t2) {
const int k = 5;
return std::get<k>(t1) < std::get<k>(t2); // or use a custom compare function
});
#include <tuple>
#include <utility>
#include <cstddef>
#include <algorithm>
#include <cstddef>
#include <iterator>
template <std::size_t I, typename It, typename F>
void sort_tuple(It it, It end, F f)
{
std::stable_sort(it, end, [f](const auto& t1, const auto& t2)
{
return f(std::get<I>(t1), std::get<I>(t2));
});
}
template <typename It, typename F, std::size_t... Is>
void sort_tuple(It it, It end, F f, std::index_sequence<Is...>)
{
int dummy[] = { 0, (sort_tuple<sizeof...(Is) - Is - 1>(it, end, f), 0)... };
static_cast<void>(dummy);
}
template <typename It, typename F>
void sort_tuple(It it, It end, F f)
{
sort_tuple(it, end, f, std::make_index_sequence<
std::tuple_size<typename std::iterator_traits<It>::value_type>::value
>{});
}
Test:
std::vector<std::tuple<int, int, int>> v{ {2,1,2}, {2,2,2}, {3,2,1}
, {1,1,1}, {1,2,1}, {2,2,1} };
sort_tuple(begin(v), end(v), [](const auto& t1, const auto& t2)
{
return t1 < t2;
});
for (auto& t : v)
{
std::cout << std::get<0>(t) << " " << std::get<1>(t) << " " << std::get<2>(t) << std::endl;
}
DEMO
You are using k as a template argument so it must be available at compile time. One way to do this by making it a constexpr:
constexpr int k = 1;
int j = k;
while(j--){
std::sort(begin(v), end(v), [&k](auto const &t1, auto const &t2) {
return get<k>(t1) < get<k>(t2); // or use a custom compare function
})
}
Template non-type arguments must be compile time constants. int k=0; is not a compile time constant.
template<std::size_t...Is>
auto index_over(std::index_sequence<Is...> ={}){
return [](auto&&f)->decltype(auto){
return f( std::integal_constant<std::size_t,Is>{}... );
};
}
template<std::size_t N>
auto index_upto(std::integral_constant<N> ={}){
return index_over(std::make_index_sequence<N>{});
}
these are helpers to get efficient compile time values from 0 up to N-1.
auto foreacher=[](auto&&f){
return [f](auto&&...args){
using discard=int[];
(void)discard{0,(void(
f(decltype(args)(args))
),0)...};
};
};
the above is obscure c++14 to replace short c++17 code. foreacher(f) returns a function g. g(a,b,c) does f(a) then f(b) then f(c).
Now glue it together:
auto sort_v_by_k=[&](auto k){
std::sort(begin(v), end(v), [](auto const &t1, auto const &t2) {
return get<k>(t1) < get<k>(t2); // or use a custom compare function
});
};
index_upto<11>()( foreacher( [&](auto k){
sort_v_by_k( std::integral_constant<std::size_t, 11-k >{} );
}));
and ignoring typos, done.

Custom range for boost::range library

I’m writing filter and map algorithms using boost::range library:
template <class Range> struct Converter
{
Converter(const Range& p_range) : m_range(p_range) {}
template<class OutContainer> operator OutContainer() const
{
return {m_range.begin(), m_range.end()};
}
private:
Range m_range;
};
template<class Range> Converter<Range> convert(const Range& p_range) { return {p_range}; }
template<class Range, class Fun> auto map(Range&& p_range, Fun&& p_fun)
{
return convert(p_range | boost::adaptors::transformed(p_fun));
}
template<class Range, class Pred> auto filter(Range&& p_range, Pred&& p_pred)
{
return convert(p_range | boost::adaptors::filtered(p_pred));
}
Right now I can use them like this:
std::vector<int> l_in = {1, 2, 3, 4, 5};
std::vector<int> l_tmp_out = filter(l_in, [](int p){ return p < 4; });
std::vector<int> l_out = map(l_tmp_out, [](int p){ return p + 5; });
I would also like to write code this way:
map(filter(l_in, [](int p){ return p < 4; }), [](int p){ return p + 5; });
Unfortunately my Converter class does not compose with boost::range algorithms so this example does not compile. I'm looking for a proper way to change that.
UPDATE
I followed #sehe link and it turned out that all I had to do was to add this four lines to Converter class:
using iterator = typename Range::iterator;
using const_iterator = typename Range::const_iterator;
auto begin() const { return m_range.begin(); }
auto end() const { return m_range.end(); }
Here's my take on things:
Live On Coliru
#include <boost/range.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <iostream>
#include <vector>
namespace MyRange {
template <typename R> struct Proxy {
Proxy(R&& r) : _r(std::move(r)) {}
Proxy(R const& r) : _r(r) {}
template <typename OutContainer> operator OutContainer() const {
return boost::copy_range<OutContainer>(_r);
}
using iterator = typename boost::range_mutable_iterator<R>::type;
using const_iterator = typename boost::range_const_iterator<R>::type;
auto begin() const { return range_begin(_r); }
auto end() const { return range_end(_r); }
auto begin() { return range_begin(_r); }
auto end() { return range_end(_r); }
private:
R _r;
};
template <typename R> auto make_proxy(R&& r) { return Proxy<R>(std::forward<R>(r)); }
template <typename Range, typename Fun> auto map(Range&& p_range, Fun&& p_fun) {
return make_proxy(std::forward<Range>(p_range) | boost::adaptors::transformed(std::forward<Fun>(p_fun)));
}
template <typename Range, typename Pred> auto filter(Range&& p_range, Pred&& p_pred) {
return make_proxy(std::forward<Range>(p_range) | boost::adaptors::filtered(std::forward<Pred>(p_pred)));
}
}
int main() {
using namespace MyRange;
{
std::vector<int> l_in = {1, 2, 3, 4, 5};
std::vector<int> l_tmp_out = filter(l_in, [](int p){ return p < 4; });
std::vector<int> l_out = map(l_tmp_out, [](int p){ return p + 5; });
boost::copy(l_out, std::ostream_iterator<int>(std::cout << "\nfirst:\t", "; "));
}
{
boost::copy(
map(
filter(
std::vector<int> { 1,2,3,4,5 },
[](int p){ return p < 4; }),
[](int p){ return p + 5; }),
std::ostream_iterator<int>(std::cout << "\nsecond:\t", "; "));
}
}
Prints
first: 6; 7; 8;
second: 6; 7; 8;
NOTES
it uses std::forward<> more accurately
it uses const/non-const iterators
it uses Boost Range traits (range_mutable_iterator<> etc.) instead of hardcoding assuming nested typedefs. This allows things to work with other ranges (e.g. std::array<> or even int (&)[]).
the user-defined converson operator uses boost::copy_range<> for similar reasons

Overloading std::transform algorithm

Consider this standard use of std::transform algorithm:
vector<int> in = { 1, 2, 3 };
auto f0 = [](int val) { return val + 1; };
auto f1 = [](int val) { return val > 1; };
vector<int> out0(in.size());
std::transform(in.begin(), in.end(), out0.begin(), f0);
vector<bool> out1(in.size());
std::transform(in.begin(), in.end(), out1.begin(), f1);
This works fine but is long to write. I would like to write something like this:
auto out0 = tranform(in, f0);
auto out1 = tranform(in, f1);
How to overload the transform algorithm to allow this syntax?
The following should do what you want
#include <algorithm>
#include <iostream>
#include <type_traits>
#include <vector>
template<typename T, typename F>
std::vector<typename std::result_of<F(T)>::type>
transform(const std::vector<T>& l, F func)
{
typedef typename std::result_of<F(T)>::type FunctorReturnType;
std::vector<FunctorReturnType> out(l.size());
std::transform(l.begin(), l.end(), out.begin(), func);
return out;
}
int main ()
{
const std::vector<int> in{ 1, 2, 3 };
auto f0 = [](int val) { return val + 1; };
auto f1 = [](int val) { return val > 1; };
auto out0 = transform(in, f0);
auto out1 = transform(in, f1);
for (const auto& m: out0) std::cout << m << std::endl;
for (const auto& m: out1) std::cout << m << std::endl;
}
Do you like template template arguments? This works with more containers than vectors.
template<template<class...> class C, class F, class T, class... Tail>
C<typename result_of<F(T)>::type>
transform(const C<T, Tail...>& in, F func)
{
C<typename result_of<F(T)>::type> out(in.size());
std::transform(in.begin(), in.end(), out.begin(), func);
return out;
}
Can be seen working at http://coliru.stacked-crooked.com/a/767adb662d7cbe42
EDIT: changed to not use the source's allocator in the resulting container.
Why aren't you ok with the following, which doesn't use any C++11 magic such as decltype ?
#include <algorithm>
#include <vector>
template<class T, class F>
std::vector<T> transform(const std::vector<T>& l, F func)
{
std::vector<T> out(l.size());
std::transform(l.begin(), l.end(), out.begin(), func);
return out;
}

Best way to emulate something like conditional_back_inserter?

I wanted to replace the loop with an algorithm in the following code
int numbers[] = { ... };
vector<int> output;
for( int* it = numbers+from; it != numbers+to ; ++it )
{
int square = func( *it );
if( predicate(square) )
{
output.push_back(square);
}
}
The program is meant to transform the values and copy them to a destination if a condition occurs.
I could not use std::copy_if because that would not apply a transformation.
I could not use std::transform because that lacks a predicate
It is not even a good idea to write a transform_copy_if() , because of the intermediate copy of the transformed variable.
It looks like my only hope is to create a conditional_back_insert_iterator. Then I could have a pretty decent call like:
int numbers[] = { ... };
vector<int> output;
std::transform(numbers+from, numbers+to,
conditional_back_inserter(predicate, output),
func);
Is this solution the best way to treat such cases ? I couldn't even google for conditional inserters, so I am worried I'm on the wrong path.
I could also imagine that I could implement an alternative solution such as
std::copy_if( transform_iterator<func>(numbers+from),
transform_iterator<func>(numbers+to),
back_inserter(output) );
(which reminds me of an example of *filter_iterators* in boost)
but that does not offer readability.
I think creating your own iterator is the way to go:
#include <iostream>
#include <vector>
#include <iterator>
#include <functional>
template<class T>
class conditional_back_insert_iterator
: public std::back_insert_iterator<std::vector<T>>
{
private:
using Base = std::back_insert_iterator<std::vector<T>>;
using Container = std::vector<T>;
using value_type = typename Container::value_type;
public:
template<class F>
conditional_back_insert_iterator(Container& other, F&& pred)
: Base(other), c(other), predicate(std::forward<F>(pred))
{ }
conditional_back_insert_iterator<T>& operator*()
{ return *this; }
conditional_back_insert_iterator<T>&
operator=(const value_type& val) const
{
if (predicate(val))
c.push_back(val);
return *this;
}
conditional_back_insert_iterator<T>&
operator=(value_type&& val) const
{
if (predicate(val))
c.push_back(std::move(val));
return *this;
}
private:
Container& c;
std::function<bool (const value_type&)> predicate;
};
template<
class Container,
class F,
class value_type = typename Container::value_type
>
conditional_back_insert_iterator<value_type>
conditional_back_inserter(Container& c, F&& predicate)
{
return conditional_back_insert_iterator<value_type>(c, std::forward<F>(predicate));
}
int main()
{
std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9};
std::vector<int> to;
auto is_even = [] (int x) { return (x % 2) == 0; };
std::copy(v.begin(), v.end(), conditional_back_inserter(to, is_even));
}
Here's my attempt.
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
template <class Container, class Pred>
class conditional_insert_iterator
: public std::iterator< std::output_iterator_tag, void, void, void, void >
{
public:
explicit conditional_insert_iterator(Container& c, Pred p) : container(&c), pred(p) {}
conditional_insert_iterator& operator=(typename Container::const_reference value) {
if (pred(value))
container->push_back(value);
return *this;
}
conditional_insert_iterator& operator*() {return *this;}
conditional_insert_iterator& operator++() {return *this;}
conditional_insert_iterator& operator++(int) {return *this;}
private:
Container* container;
Pred pred;
};
template< class Container, class Pred>
conditional_insert_iterator<Container, Pred> conditional_inserter( Container& c, Pred pred )
{
return conditional_insert_iterator<Container, Pred>(c, pred);
}
using namespace std;
int main()
{
vector<int> in = { 1, 2, 3, 4, 5, 6 };
vector<int> out;
transform(in.begin(), in.end(),
conditional_inserter(out, [](int i) { return i%2 == 0;}),
[](int i) { return i + 2;});
for (auto i : out)
cout << i << "\n";
return 0;
}