I am trying to declare in a function a new vector with the value type from an iterator like the following. If this function is not recursive it is compiling but when the function is calling it self does not compile.
template<typename ForwardIterator>
auto Foo(ForwardIterator f, ForwardIterator l) {
typedef typename iterator_traits<ForwardIterator>::value_type T;
auto n = distance(f,l);
vector<T> v(n);
auto h = n /2;
auto m = next(f,h);
auto vr = Foo(f,m); // If this line is commented it is compiling
return v;
}
int main() {
vector<int> v = { 38, 27, 43, 3, 9, 82, 10 };
auto rv = Foo(v.begin(), v.end());
return 0;
}
Your compiler seems to fail to deduce auto type. You could help it to deduce return type by implementing iterator_type2vector_type helper class.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
template<typename ForwardIterator>
struct iterator_type2vector_type {
typedef typename std::iterator_traits<ForwardIterator>::value_type value_type;
typedef std::vector<value_type> vector_type;
};
template<typename ForwardIterator>
typename iterator_type2vector_type<ForwardIterator>::vector_type
Foo(ForwardIterator begin, ForwardIterator end) {
typedef typename iterator_type2vector_type<ForwardIterator>::vector_type vector_type;
// add your code here.
return vector_type(begin, end);
}
int main() {
auto a = {1, 2 ,3, 4};
auto result = Foo(std::begin(a), std::end(a));
std::copy(std::begin(result), std::end(result), std::ostream_iterator<int>(std::cout, ", "));
return 0;
}
auto return type is c++14 feature, so with this changes you would go with c++11.
Related
I need to create a constexpr template function to sum container, and pass the static assert. This is my code, but I have to questions.
I recived this error: assignment of read-only reference ‘res’.
Is the sum function written correctly?
#include <iostream>
#include <array>
using namespace std;
template <typename T>
constexpr auto Sum(const T& arr)
{
using arrType = decltype(*arr.begin());
arrType res = 0;
for (auto it = arr.begin(); it != arr.end(); it++) {
res += *it;
}
return res;
}
int main()
{
constexpr array<int, 3> base{5, 2, 0};
static_assert(Sum(base) == 7);
return 0;
}
Your code doesn't compile because since arr is const reference, decltype(*arr.begin()) is const int. So your res is const and you can't assign to it in your loop.
To fix only that error, you should use std::decay, i.e:
using arrType = std::decay_t<decltype(*arr.begin())>;
You don't specify what you mean by "container". If you mean the standard library's definition (which is supported by all STL containers), you can use value_type instead and also further simplify your code:
template <typename T>
constexpr auto Sum(const T& arr) {
typename T::value_type result{};
for (auto const& x : arr) {
result += x;
}
return result;
}
If you have C++20, you can also use std::accumulate:
template <typename T>
constexpr auto Sum(const T& arr)
{
return std::accumulate(arr.begin(), arr.end(),
typename T::value_type{});
}
The problem lies with decltype(*arr.begin()), which gives const U& if U represents the type of the elements of the container arr.
Applying std::remove_reference and std::remove_cv makes it compile.
#include <iostream>
#include <type_traits>
#include <array>
using namespace std;
template <typename T>
constexpr auto Sum(const T& arr)
{
using arrType = remove_cv_t<remove_reference_t<decltype(*arr.begin())>>;
arrType res = 0;
for (auto it = arr.begin(); it != arr.end(); it++) {
res += *it;
}
return res;
}
int main()
{
constexpr array<int, 3> base{5, 2, 0};
static_assert(Sum(base) == 7);
return 0;
}
I'm experimenting with the "find" function. I can't seem to be able to return
the iterator.
template<typename T>
typename T::iterator do_find(const T &v, int f)
{
return find(v.begin(), v.end(), f);
}
And here is my main :
int main()
{
std::vector<int> v = {1, 2, 3, 3, 4, 6};
std::vector<int>::iterator it;
it = do_find(v, 3);
return 0;
}
When I compile I get the following error :
error: impossible de convertir
« std::find<__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, int>((& v)->std::vector<int>::begin(), (& v)->std::vector<int>::end(), f) » de « __gnu_cxx::__normal_iterator<const int*, std::vector<int> > » vers « std::vector<int>::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >} »
v is declared as const, then for std::vector, both v.begin() and v.end() return std::vector::const_iterator, then the return type of find will be std::vector::const_iterator too; it can't be converted to std::vector::iterator implicitly.
You can change the return type, e.g.
template<typename T>
typename T::const_iterator do_find(const T &v, int f)
{
return find(v.begin(), v.end(), f);
}
or just
template<typename T>
auto do_find(const T &v, int f)
{
return find(v.begin(), v.end(), f);
}
then
auto it = do_find(v, 3);
If you want to modify the element through the returned iterator, then you should declare the parameter v to be non-const.
template<typename T>
auto do_find(T &v, int f)
{
return find(v.begin(), v.end(), f);
}
Note that with auto, the above do_find will return iterator if you pass a non-const vector, and return const_iterator if you pass a const vector.
v is const; meaning that std::find will return a T::const_iterator. You're attempting to return a T::iterator; and the compiler can't convert from const to non-const.
The fix is to either return the const_iterator or to make v non-const. Depending on exactly what you want to do with the iterator.
Within the function the container is declared as a constant container
template <typename T>
typename T::iterator do_find(const T &v, int f);
^^^^^^^^^^
So the member functions begin and end of this container return objects of the type typename T::const_iterator that can not be implicitly converted to the type.typename T::iterator.
Also it is not clear why the second parameter has the type int instead of the type typename T::value_type.
There is a magic word auto in C++ that can simplify the function declaration and using its return value.
The function can be defined the following way
template <typename T>
auto do_find( const T &v, typename T::value_type value ){
return std::find( v.begin(), v.end(), value );
}
Here is a demonstrative program
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
template <typename T>
auto do_find( const T &v, typename T::value_type value ){
return std::find( v.begin(), v.end(), value );
}
int main()
{
std::vector<int> v = { 1, 2, 3, 3, 4, 6 };
auto it = do_find(v, 3);
if ( it != v.end() )
{
std::cout << *it << " is found at position "
<< std::distance( v.cbegin(), it ) << std::endl;
}
return 0;
}
Its output is
3 is found at position 2
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;
}
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.
Say, I have vector of elements and a mask array, and I want to extract elements from vector with true corresponding mask value to separate vector. Is there a way to use std::copy_if for this purpose? The problem is, I only have value of element inside predicate, not iterator to it, so I cannot know the actual index to address mask array.
I can directly manipulate addresses like this:
vector<bool> mask;
vector<int> a, b;
copy_if(a.begin(), a.end(), b.begin(), [&] (int x) -> bool {
size_t index = &x - &a[0]; // Ugly...
return mask[index];
});
However, I find this to be ugly solution. Any better ideas?
Update: Another possible solution is to use external iterator on mask:
vector<bool> mask;
vector<int> a, b;
auto pMask = mask.begin();
copy_if(a.begin(), a.end(), b.begin(), [&] (int x) {
return *pMask++;
});
However, this solution requires additional variable in outer namespace which still is not desirable.
Ok, after a bit of investigation I come out with the first example be the easiest way. However, one should not forget to pass value in lambda by (const) reference for not to take address of local copy of a parameter:
copy_if(a.begin(), a.end(), b.begin(),
[&] (const int& x) -> bool { // <-- do not forget reference here
size_t index = &x - &a[0]; // Still ugly... but simple
return mask[index];
});
My answer:
vector<bool> mask ;
vector<int> a, b;
auto it = std::copy_if (a.begin(), a.end(), b.begin(), [&, index = 0] (const int x) mutable -> bool {
return mask[index++]; // increment index
});
This uses a state-full lambda.
index is set to zero just once and incremented every time it is used.
edit:
requires c++14
You could combine several iterators form Boost (not really tested, but compiles with GCC 4.6):
#include <algorithm>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/iterator/zip_iterator.hpp>
#include <boost/iterator/filter_iterator.hpp>
#include <boost/tuple/tuple.hpp>
int main() {
std::vector<bool> mask;
std::vector<int> a, b;
boost::counting_iterator<size_t> count_begin(0), count_end(a.size());
auto zip_begin = boost::make_zip_iterator(boost::make_tuple(count_begin, a.begin()));
auto zip_end = boost::make_zip_iterator(boost::make_tuple(count_end, a.end()));
typedef decltype(zip_end) zip_iterator;
typedef const zip_iterator::value_type& zip_value;
auto pred = [&mask](zip_value val) {
auto index = val.get<0>();
return index < mask.size() ? mask[index] : true;
};
auto filter_begin = boost::make_filter_iterator(pred, zip_begin, zip_end);
auto filter_end = boost::make_filter_iterator(pred, zip_end, zip_end);
std::transform(filter_begin, filter_end, back_inserter(b), [](zip_value val) {
return val.get<1>();
});
}
However, I think an explicit loop is just simpler here.
Here is another more generalized version of the above code, this time even tested :)
It provides implementations for Python-like map, filter and enumerate functions. This one requires GCC 4.7.
#include <utility>
#include <vector>
#include <iterator>
#include <type_traits>
#include <iostream>
#define BOOST_RESULT_OF_USE_DECLTYPE
#include <boost/tuple/tuple.hpp>
#include <boost/iterator/zip_iterator.hpp>
#include <boost/iterator/filter_iterator.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/range/counting_range.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/range/algorithm_ext/push_back.hpp>
template<typename... ForwardRange>
using zip_range = boost::iterator_range<
boost::zip_iterator<
boost::tuple<
typename boost::range_iterator<
typename std::remove_reference<ForwardRange>::type>::type...>>>;
template<typename... ForwardRange>
zip_range<ForwardRange...>
zip(ForwardRange&&... ranges) {
return boost::make_iterator_range(
boost::make_zip_iterator(
boost::make_tuple(
boost::begin(std::forward<ForwardRange>(ranges))...)),
boost::make_zip_iterator(
boost::make_tuple(
boost::end(std::forward<ForwardRange>(ranges))...)));
}
template<typename ForwardRange, typename Index>
using enumerating_range = zip_range<
boost::iterator_range<boost::counting_iterator<Index>>,
ForwardRange>;
template<typename ForwardRange, typename Index>
enumerating_range<ForwardRange, Index>
enumerate(ForwardRange&& range, Index start) {
return zip(
boost::counting_range(
start,
static_cast<Index>(start + boost::size(range))),
std::forward<ForwardRange>(range));
}
template<typename Predicate, typename ForwardRange>
using filter_range = boost::iterator_range<
boost::filter_iterator<
Predicate,
typename boost::range_iterator<
typename std::remove_reference<ForwardRange>::type>::type>>;
template<typename Predicate, typename ForwardRange>
filter_range<Predicate, ForwardRange>
filter(Predicate pred, ForwardRange&& range) {
return boost::make_iterator_range(
boost::make_filter_iterator(
pred,
boost::begin(std::forward<ForwardRange>(range))),
boost::make_filter_iterator(
pred,
boost::end(std::forward<ForwardRange>(range))));
}
template<typename UnaryOperation, typename ForwardRange>
using map_range = boost::iterator_range<
boost::transform_iterator<
UnaryOperation,
typename boost::range_iterator<
typename std::remove_reference<ForwardRange>::type>::type>>;
template<typename UnaryOperation, typename ForwardRange>
map_range<UnaryOperation, ForwardRange>
map(UnaryOperation operation, ForwardRange&& range) {
return boost::make_iterator_range(
boost::make_transform_iterator(
boost::begin(std::forward<ForwardRange>(range)),
operation),
boost::make_transform_iterator(
boost::end(std::forward<ForwardRange>(range)),
operation));
}
template<typename UnaryOperation, typename Predicate, typename ForwardRange>
using filter_map_range = map_range<
UnaryOperation,
filter_range<Predicate, ForwardRange>>;
template<typename UnaryOperation, typename Predicate, typename ForwardRange>
filter_map_range<UnaryOperation, Predicate, ForwardRange>
filter_map(UnaryOperation operation, Predicate pred, ForwardRange&& range) {
return map(operation, filter(pred, range));
}
int main() {
std::vector<int> a { 10, 11, 12, 13, 14 };
std::vector<bool> mask { false, true, true, false, true };
std::vector<int> b;
auto enumerator = enumerate(a, 0u);
typedef boost::range_value<decltype(enumerator)>::type enum_value;
boost::push_back(
b,
filter_map(
[](const enum_value& val) {
return val.get<1>();
},
[&mask](const enum_value& val) {
auto i = val.get<0>();
return i < mask.size() ? mask[i] : true;
},
enumerator));
boost::copy(b, std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
}
If you aren't required to use vectors, the solution becomes somewhat boring:
#include <valarray>
#include <algorithm>
#include <iterator>
#include <iostream>
int main() {
using namespace std;
valarray<int> a { 10, 11, 12, 13, 14 };
valarray<bool> mask { false, true, true, false, true };
valarray<int> b = a[mask];
copy(begin(b), end(b), ostream_iterator<int>(cout, " "));
}