for_each accepts InputIterators :
//from c++ standard
template <class InputIterator, class Function>
Function for_each (InputIterator first, InputIterator last, Function f);
is it ok to change the object in Function f, like this :
struct AddOne
{
void operator()(int & x){x = x + 1;}
};
std::vector<int> vec(10);
std::for_each(vec.begin(),vec.end(),AddOne());
This code works in VC++2008 and also with GCC, but is it also portable (legal) code ?
(InputIterators are only guaranteed to be usable as rvalue, in this case they are used as lvalue in AddOne's operator())
Read this article.
To be pedantic: for_each is a non-modifying sequence operation. The intent is not to modify the sequence. However, it is okay to modify the input sequence when using for_each.
You misunderstand something. Saying input iterators are only guaranteed to be usable as rvalues doesn't mean you can't get an lvalue out of an iterator somehow. So it does not mean that the result of *iterator is an rvalue. What you/for_each passes to AddOne is the result of operator* - not the iterator itself.
About for_each and a modifying function object - read this question
If in doubt use std::transform as it will convey even to the casual reader of your code that you intend to modify something.
It is legal - the input iterators are used to specify the range, not to do the processing.
Interestingly, Josuttis in his book "The C++ Standard Library" lists for_each as modifying, raher than non-modifying.
My suggestion would be, it all matters how you pass your item to the function i.e. whether by reference or pointer and change it or as a copy and change it.
But as other's have said, if you want to change the values, it's better to use transform as it cares about the return values.
class MultiplyBy {
private:
int factor;
public:
MultiplyBy(int x) : factor(x) {
}
int operator () (int other) const {
other = factor + other;
return other;
}
// int operator () (int & other) const {
// other = factor + other;
// return other;
// }
};
vector<int> x1= {1, 2, 3, 4, 5};
vector<int> x2;
std::transform(x1.begin(), x1.end(), back_inserter(x2), MultiplyBy(3));
std::for_each(x1.begin(), x1.end(), MultiplyBy(3));
Related
I have a vector that looks like this.
std::vector<std::pair<int,int> > v;
and I want to pass it into a function and make it so it's constant.
first I tried
void fun(const std::vector<std::pair<int,int> > v)
but that function allowed me to have the line
std::pair<int,int> p = v[i];
which I thought should have thrown an error since pair is not of type const. Then I realized that it's only the pointers that are being declared constant in vector so I tried
void fun(const std::vector<const std::pair<int,int> > v)
but that throws the error about there being no conversion.
I'm sure there's some inner workings that I'm not understanding that makes this illegal but would love some insight. Thanks.
I think you confuse reference and value semantics here. Lets the first function signature you tested:
void fun(const std::vector<std::pair<int,int> > v)
This copies the function argument into a new object v, which is additionaly const-qualified. Such signatures seldomly make sense: either you want to pass it as a const reference (to avoid copying) or you want to pass it by non-const value, because the function body will mutate the argument, but shall operate on its only copy. Besides, this snippet:
std::pair<int,int> p = v[i];
compiles just fine with the above function signature, because it copies the vector element at position i into a new pair object. The latter can be mutated, but this doesn't affect the vector at all.
Let's now consider the second function signature:
void fun(const std::vector<const std::pair<int,int> > v)
The same as before still applies here, and in addition, std::vector<const T> isn't useful, see this thread for an explanation.
How to fix it? If you don't want to copy the argument, but the function doesn't modify the vector, pass it by const reference. If the function modifies the vector and these modifications shall be visible at the call side, pass it as non-const reference. If the function modifies the vector but that shall happen independently of the call side vector, pass by non-const value.
void fun(const std::vector<std::pair<int,int> > v)
{
////
std::pair<int,int> p = v[i];
}
https://en.cppreference.com/w/cpp/container/vector/operator_at
No error will happen here because std::vector has overloaded operator[] both for const and non-const instances. In your case it will be resolved to const version and return const & to underlying i element.
Consider following code:
void fun(const std::vector<std::pair<int,int> > v)
{
////
std::pair<int,int> p = v[i]; //OK
v[i] = std::pair<int,int>{10,20}; //Compile error, trying to modify const data!
}
I am trying to add a reference to std algorithm. How can I edit my code to make it working?
double f(const std::vector<double> &arr, bool maxElem)
{
auto me = maxElem ? std::max_element : std::min_element;
//...
x = me(arr.begin(), arr.end());
//...
}
Your functions are template functions so you have to specify the template parameter. In this case, using a std::vector you need to pass them iterators:
Also, to cope with different potential overloads of the functions we should cast them to the type we require (thnx to #ChristianHackl):
double f(const std::vector<double>& arr, bool maxElem)
{
// deduce the iterator parameter types
using Iterator = decltype(arr.begin());
// select the overload type
using Overload = Iterator(*)(Iterator, Iterator);
auto me = maxElem
? static_cast<Overload>(std::max_element<Iterator>)
: static_cast<Overload>(std::min_element<Iterator>);
// need to dereference this because `me` returns an iterator
return *me(arr.begin(), arr.end());
}
Also note I dereference the return value from me() because it is an iterator (like a pointer).
Of course if your vector is empty that will dereference an invalid location so I recommend putting in a check:
double f(const std::vector<double>& arr, bool maxElem)
{
// Avoid Undefined Behavior
if(arr.empty())
throw std::runtime_error("empty vector not allowed");
// deduce the parameter types
using Iterator = decltype(arr.begin());
// select the overload type
using Overload = Iterator(*)(Iterator, Iterator);
auto me = maxElem
? static_cast<Overload>(std::max_element<Iterator>)
: static_cast<Overload>(std::min_element<Iterator>);
// need to dereference this because `me` returns an iterator
return *me(arr.begin(), arr.end());
}
Like this:
if (maxElem)
return std::max_element(arr.begin(), arr.end());
else
return std::min_element(arr.begin(), arr.end());
You could probably obtain a reference to the template specialisation of each "algorithm" you're trying to use, but due to the need to specify template arguments it would be messy and verbose, and thus a false economy. It may also carry a performance penalty (ruining inlineability).
It doesn't really make sense for f to behave like this in the first place; try to make your functions do one thing well. Arguably, their underlying semantics shouldn't depend on an argument like this.
Suppose we have function f that that takes integer number and returns a value that increases monotonically. We want find minimal x such that f(x) >= C. For simplicity let's say that answer is in range [l;r) Obviously we can write our own implementation of binary search but we want to use existing one (std::patition_point).
So naive implementation that will (probably) work:
// f;
std::vector<int> v(r - l);
std::iota(v.begin(), v.end(), l);
answer = l + partition_point(v.begin(), v.end(), [&](int x) {
return f(x) <= C;
}) - v.begin();
The obvious problem is that we have to store all the numbers which takes a lot of memory and also takes time to fill the array
Next logical idea is to wrap integer to iterators in this way:
struct IntIterator: std::iterator<std::random_access_iterator_tag, int> {
int current;
IntIterator(int i) : current(i) {}
int operator*() const { return current; }
IntIterator& operator++() { ++current; return *this; }
IntIterator& operator+=(size_t n) { current += (int)n; return *this; }
IntIterator operator+(size_t n) const { return current+(int)n; }
size_t operator-(IntIterator that) const { return size_t(current - that.current); }
// others operators to conform
};
answer = partition_point(IntIterator{l}, IntIterator{r}, [&](int x) {
return f(x) <= C;
});
This will work with my compiler (standard library) but is not conforming random access iterator because
operator* should return std::iterator_traits<IntIterator>::reference.
if we change std::iterator_traits<IntIterator>::reference to int (for example by changing template parameters to std::iterator) it will not satisfy requirement of forward iterator:
if X is a mutable iterator, reference is a reference to T; if X is a const iterator, reference is a reference to const T,
if we change return type of operator* to [const ]T& it will fail to satisfy another requirement of forward iterator
If a and b are both dereferenceable, then a == b if and only if *a and *b are bound to the same object.
So I don't understand how to make it conforming and question arise whether it's possible.
The iterators share a pointer to a cache map.
The cache map maps index to (count, value), where count is the number of iterators at that index.
The iterator remembers if it called *.
When * is called, the value is populated if missing. Regardless, count is incremented, then a reference to value is returned.
When the iterator is destroyed, or the iterator moves (++), if * was called, count is decremented.
If count is decremented to zero, the entry is removed.
This caches the values for all valid iterators of the same index during their collective overlapping lifetime.
if X is a mutable iterator, reference is a reference to T; if X is a const iterator, reference is a reference to const T
I think that you shouldn't take this requirement too seriously. Standard library contains a container (std::vector<bool>) whose const_iterator and iterator fail to meet this requirement. I know that there is a point of view that "std::vector<bool> IS NOT a Container", but I am more inclined to see the quoted requirement as too restrictive, than to fully agree with that point of view.
So, in order to allow code such as
auto vect = ...;
auto it = vect.begin(), end = vect.end(); // want const_iterator, getting iterator
to pick the right overload of begin() and end(), even for non-const containers, the more explicit cbegin()/cend() functions were added.
Why stop there?
Associative containers have a find() method with the same problem. Sequence containers have front() and back(), again with the same problem.
Are these missing explicit const versions omissions, or by design?
A wider API has cost, even just to skip over it when looking for the function you want.
template<class T>
T const as_const(T&& t) noexcept(noexcept(T(std::declval<T>())) {
return std::forward<T>(t);
}
template<class T>
T const& as_const(T& t) noexcept {
return t;
}
does most of what you want. It would even make cbegin obsolete.
(modifications done to the code above based off n4380 supplied by #T.C below. Code differs, because I think n4380 got it slightly wrong in the T&& case.)
The purpose of cbegin/cend is to solve a specific problem. Consider this code:
std::vector<int> & v = //... v is a non-const reference
// For clarity, I want this iterator to be a const_iterator.
// This works because iterator is implicitly convertible to const_iterator
std::vector<int>::const_iterator iter = find(v.begin(),v.end(),42);
// (1) Now I want to use iter in an algorithm
std::find(iter, v.end(), 38); //Error, can not deduce the template parameter for Iter.
// (2) This works
std::find(iter, const_cast<const std::vector<int> &>(v).end(), 38);
// (3) This is the same as (2).
std::find(iter, v.cend(), 38);
The problem is that, due to how template deduction rules work, the compiler can not deduce the template iterator argument in the statement (1), because Container::iterator and Container::const_iterator are (potentially) two completely unrelated types (even if the former is implicitly convertible in the latter).
The statement (2) is not exactly a beautiful line, that is why we need cend().
Now, front(), back() et similia all return a reference. A non-const reference can always be deduced as const in a templated function, that is:
template<class T> void f( const T & l, const T & r);
int main()
{
int x; vector<int> v;
//This will works even if the return type of front() is int&.
f(x, v.front());
}
Since Container::const_reference is required by the standard to be equal to const Container::value_type &, cfront()/cback() do not buy us anything.
It is worth mentioning that other containers library (looking at you Qt) are implemented using Copy-On-Write.
This means that calling a const function on such container is potentially much less expensive than calling the equivalent non-const version, simply because the non-const might copy the entire container under the hood.
For this reason the Qt containers have a lot of constFunction in their interface, and the user has the freedom to pick the right one.
I want to write my own 2d array class. I want the class to be able to assign a value to an element like this.
a(0,0) = 1
I know this must be possible because I can do it with the matrix classes from blaze and eigen. My first idea was to overload the function operator (), which already works great to access the elements. When I try to assign a value with a(0,2) = 0; I get a compiler error.
lvalue required as left operand of assingment
What operator do I have to overload that the assignment also works?
You need to build a function with this prototype:
T& operator()(std::size_t, std::size_t);
Where T is your element type. This function needs to return a reference to an element in the array. This allows you to modify the value of the element via that reference in the caller.
As well as the above, you ought to provide the function
const T& operator()(std::size_t, std::size_t) const;
for read-only element access. I've rather dogmatically insisted on std::size_t for your indexing. In reality, you might want a typedef of your own to stand in for the index type.
You need to provide two overloads - one const and another one not, returning a reference. For example:
template <typename TVal> class val {
std::map<int, TVal> values;
public:
// the distinction is between a const version ...
TVal operator()(int key) const {
auto found = values.find(key);
if (found != values.end())
return found->second;
return TVal();
}
// ... and a non-const, returning a reference
TVal& operator()(int key) {
return values[key];
}
};
and then you can use it as follows:
val<int> v;
v(1) = 41;
v(1)++;
std::cout << v(1) << std::endl; // -> 42
std::cout << v(2) << std::endl; // -> 0
Please post the compile-error, for others to see and precisely answer it.
Having said that, I am pretty sure that it is because you are not returning a reference from your operator.