stl::find_if with user search - c++

I was wondering if there was a way to use the stl::find_if to search for a user inputted value
I don't know to do that without using any bad conventions(globals) or adding loads of extended code.
For example, if a user inputs a int x for 10, then I want to search an vector of ints
iterator = find_if(begin,end,pred) //but how does pred know the user inputted value?

You can use equal_to:
find_if(a.begin(), a.end(), bind2nd(equal_to<int>(), your_value));

The pred must be an instance of a type that has the overloaded () operator, so it can be called like a function.
struct MyPred
{
int x;
bool operator()(int i)
{
return (i == x);
}
};
(Using a struct for brevity here)
std::vector<int> v;
// fill v with ints
MyPred pred;
pred.x = 5;
std::vector<int>::iterator f
= std::find_if(v.begin(),
v.end(),
pred);
Writing custom classes like this (with "loads" of code!) is cumbersome to say the least, but will be improved a lot in C++0x when lambda syntax is added.

You can use boost::bind, for more general solution, for example:
struct Point
{
int x;
int y;
};
vector< Point > items;
find_if( items.begin(), items.end(), boost::bind( &Point::x, _1 ) == xValue );
will find a point whose x equals xValue

Related

Spaceship operator on arrays

The following code is intended to implement comparison on an object that contains an array. Two objects should compare as <,==,> if all array elements compare like that. The following does not compile for a variety of reason:
#include <compare>
class witharray {
private:
array<int,4> the_array;
public:
witharray( array<int,4> v )
: the_array(v) {};
int size() { return the_array.size(); };
auto operator<=>( const witharray& other ) const {
array< std::strong_ordering,4 > cmps;
for (int id=0; id<4; id++)
cmps[id] = the_array[id]<=>other.the_array[id];
return accumulate
(cmps.begin(),cmps.end(),
std::equal,
[] (auto x,auto y) -> std::strong_ordering { return x and y; }
);
};
};
First of all, the array of comparisons:
call to implicitly-deleted default constructor of 'array<std::strong_ordering, 4>
Then the attempt to accumulate the comparisons:
no matching function for call to 'accumulate'
Compiler explorer: https://godbolt.org/z/E3ovh5qGa
Or am I completely on the wrong track?
Two objects should compare as <,==,> if all array elements compare like that.
This is a fairly interesting order. One thing to note here is that it's a partial order. That is, given {1, 2} vs {2, 1}, those elements aren't all < or == or >. So you're left with unordered.
C++20's comparisons do have a way to represent that: you have to return a std::partial_ordering.
The way that we can achieve this ordering is that we first compare the first elements, and then we ensure that all the other elements compare the same. If any pair of elements doesn't compare the same, then we know we're unordered:
auto operator<=>( const witharray& other ) const
-> std::partial_ordering
{
std::strong_ordering c = the_array[0] <=> other.the_array[0];
for (int i = 1; i < 4; ++i) {
if ((the_array[i] <=> other.the_array[i]) != c) {
return std::partial_ordering::unordered;
}
}
return c;
}
This has the benefit of not having to compare every pair of elements, since we might already know the answer by the time we get to the 2nd element (e.g. {1, 2, x, x} vs {1, 3, x, x} is already unordered, doesn't matter what the other elements are).
This seems like what you were trying to accomplish with your accumulate, except accumulate is the wrong algorithm here since we want to stop early. You'd want all_of in this case:
auto comparisons = views::iota(0, 4)
| views::transform([&](int i){
return the_array[i] <=> other.the_array[i];
});
bool all_match = ranges::all_of(comparisons | drop(1), [&](std::strong_ordering c){
return c == comparisons[0];
});
return all_match ? comparisons[0] : std::partial_ordering::unordered;
Which is admittedly awkward. In C++23, we can do the comparisons part more directly:
auto comparisons = views::zip_transform(
compare_three_way{}, the_array, other.the_array);
And then it would read better if you had a predicate like:
bool all_match = ranges::all_of(comparisons | drop(1), equals(comparisons[0]));
or wrote your own algorithm for this specific use-case (which is a pretty easy algorithm to write):
return all_same_value(comparisons)
? comparisons[0]
: std::partial_ordering::unordered;
Note that std::array already has spaceship operator which apparently does what you need:
class witharray {
private:
array<int, 4> the_array;
public:
witharray(array<int, 4> v)
: the_array(v) {};
int size() { return the_array.size(); };
auto operator<=>(const witharray& other) const
{
return the_array <=> other.the_array;
};
};
https://godbolt.org/z/4drddWa8G
Now to cover problems with your code:
array< std::strong_ordering, 4 > cmps; can't be initialized since there is no default value for std::strong_ordering
use of std::accumluate here is strange there is better algorithm for that: std::lexicographical_compare_three_way which was added to handle spaceship operator
You have feed std::equal to std::accumluate as binary operation when in fact this is algorithm to compare ranges (it accepts iterators). Most probably your plan here was to use std::equal_to.

Make std::set to use conversion operator when compare elements

Currently I use std::map to save key/value pairs:
#include <map>
using K = int;
struct P {}; // some useful payload
int main()
{
std::map< K, P const > m;
m.insert({1, {}});
auto it = m.find(1);
// access:
it->first;
it->second;
}
int here is just for example. mapped_type is always const in my use case.
To access payload P const I have to use not too informative name second. The same regarding first. I want to name it simply payload or somehow else.
To achieve this, I invent the following approach:
#include <set>
using K = int;
struct P {};
struct A
{
K key;
P payload;
operator K const & () const { return key; }
};
struct less
{
using is_transparent = void;
bool operator () (K const & l, K const & r) const
{
return l < r;
}
};
int main()
{
std::set< A, less > s;
s.insert({1, {}});
auto it = s.find(1);
// access:
it->key;
it->payload;
}
Here I make std::set to use conversion operator every time for the key type. It works. But is it prohibited approach? Is there undefined behaviour?
To me, it looks technically valid.
But it also falls into the category of "making your code so unnecessarily complex that a programmer has to look twice or thrice at it before they comprehend what on earth you're doing, and can validate that you're doing it correctly, and for basically no tangible benefit" which is very ungood.
Indeed, the fact that you — the code's own author, no less! — felt the need to come here asking for a language lawyer to validate the code's correctness is a big red flag that this is likely not worthwhile.
If at any point you feel that .first and .second are insufficiently descriptive for your code, you can instead get around that locally with such magic as:
auto& key = it->first;
auto& payload = it->second;
or even:
auto& payload = getPayload(it);
where getPayload is an appropriate function taking an iterator of your particular type.
These approaches have the benefit of being fairly obvious, and of not requiring convening a session of the C++ Supreme Court to check them over first.

Smart way of assigning single member from vector A to vector B

This is a piece of code I'm currently using and I was wondering if there was a more elegant way of doing this in C++11 -
Essentially vector_a is copied to vector_b, then slightly modified, then vector_b is returned.
Vector elements are of class Point which is basically (leaving out constructors and a bunch of methods):
class Point {
double x,
y,
z;
};
Ideally I'd love to boil down the assignment of member z from vector_a to vector_b to something like a line or two but couldn't come up with an elegant way of doing it.
Any suggestions welcome!
auto localIter = vector_a.begin();
auto outIter = vector_b.begin();
while (localIter != vector_a.end() && outIter != vector_b.end())
{
outIter->z = localIter->z;
localIter++;
outIter++;
}
You may use transform().
std::transform (vector_a.begin(), vector_a.end(), vector_b.begin(), vector_a.begin(), [](Elem a, Elem b) { a->z = b->z; return a; });
Where Elem is a type of vector element.
As the vector has a random access iterator (using of std::next is effective) then I would write the code the following way
auto it = vector_a.begin();
std::for_each( vector_b.begin(),
std::next( vector_b.begin(),
std::min( vector_a.size(), vector_b.size() ) ),
[&it] ( Point &p ) { p.z = it++->z; } );
A partial copy is, actually, just a transformation of the elements (one of many), and therefore std::transform is a natural fit here.
Like many algorithms acting on multiple sequences, you have to be careful about the bounds of your containers; in this particular case, since vector_b just receives stuff, the easiest is to start empty and adjust its size as you go.
Thus, in the end, we get:
vector_b.clear();
std::transform(vector_a.begin(),
vector_a.end(),
std::back_inserter(vector_b),
[](Elem const& a) { Elem b; b.z = a.z; return b; });
transform is perhaps the most generic algorithm in the Standard Library (it could imitate copy for example), so you should carefully consider whereas a more specialized algorithm exists before reaching for it. In this case, however, it just fits.
I would be tempted to do something a bit like this:
#include <vector>
struct info
{
int z;
};
int main()
{
std::vector<info> a = {{1}, {2}, {3}};
std::vector<info> b = {{4}, {5}};
for(size_t i(0); i < a.size() && i < b.size(); ++i)
b[i].z = a[i].z;
}

C++ Access an element of pair inside vector

I have a vector with each element being a pair. I am confused with the syntax. Can someone please tell me how to iterate over each vector and in turn each element of pair to access the class.
std::vector<std::pair<MyClass *, MyClass *>> VectorOfPairs;
Also, please note, I will be passing the values in between the function, hence VectorOfPairs with be passed by pointer that is *VectorOfPairs in some places of my code.
Appreciate your help. Thanks
This should work (assuming you have a C++11 compatible compiler)
for ( auto it = VectorOfPairs.begin(); it != VectorOfPairs.end(); it++ )
{
// To get hold of the class pointers:
auto pClass1 = it->first;
auto pClass2 = it->second;
}
If you don't have auto you'll have to use std::vector<std::pair<MyClass *, MyClass *>>::iterator instead.
Here is a sample. Note I'm using a typedef to alias that long, ugly typename:
typedef std::vector<std::pair<MyClass*, MyClass*> > MyClassPairs;
for( MyClassPairs::iterator it = VectorOfPairs.begin(); it != VectorOfPairs.end(); ++it )
{
MyClass* p_a = it->first;
MyClass* p_b = it->second;
}
Yet another option if you have a C++11 compliant compiler is using range based for loops
for( auto const& v : VectorOfPairs ) {
// v is a reference to a vector element
v.first->foo();
v.second->bar();
}
You can access the elements of pairs inside vector in C++17 in a following style by combining range-based for loop and structured bindings. Example:
for (auto& [x, y] : pts) {
cin >> x >> y;
}
where pts is a vector of pairs. & is used to make formal "uniquely-named variable" e of structured binding a reference so that x and y referring to subobjects of e refer to original pair inside pts, which can be modified this way (e.g. cin can be used to input to it). Without &, e would be a copy (to subobjects of which x and y again refer). Example using your VectorOfPairs:
for (auto [pFirst, pSecond] : VectorOfPairs ) {
// ...
}
Also you can make e a reference to const when modification through structured binding is not needed and you want to avoid potentially expensive copy of a pair (though this should not be a problem in your case since pair object consisting of 2 pointers is pretty small and cheap to copy). Example:
for (const auto& [pFirst, pSecond] : VectorOfPairs ) {
// ...
}

Best way to pass tuples to a function and have it return a list of number?

For example, let's say I want to pass the values (1,2),(2,3),(3,4), etc. into a function and have it return a list of numbers, whatever they may be, i.e. 1, 3, 5, 3, 6 after some operations. What is the best way to achieve this result in C++? After moving from python it seems a lot more difficult to do it here, any help?
In general, you would use the std::vector container and its method push_back. You can then return the vector (return it by value, don't bother allocating it dynamically since your compiler probably supports move-semantics).
std::vector<int> func(
const std::tuple<int, int>& a, const std::tuple <int, int>& b)
{
std::vector<int> ret;
ret.push_back(...);
ret.push_back(...);
return ret;
}
I'm not saying this is the best way but I think it is pretty good, also from the memory-copying prospective, note I avoid returning a vector (expensive since it invokes the operator= implicitly):
#include <vector>
using namespace std;
/**
* Meaningful example: takes a vector of tuples (pairs) values_in and returns in
* values_out the second elements of the tuple whose first element is less than 5
*/
void less_than_5(const vector<pair<int, int> >& values_in, vector<int>& values_out) {
// clean up the values_out
values_out.clear();
// do something with values_in
for (vector<pair<int, int> >::iterator iter = values_in.begin(); iter != values_in.end(); ++iter) {
if (iter->first < 5) {
values_out.push_back(iter->second);
}
}
// clean up the values_out (again just to be consistent :))
values_out.clear();
// do something with values_in (equivalent loop)
for (int i = 0; i < values_in.size(); ++i) {
if (values_in[i].first < 5) {
values_out.push_back(values_in[i].second);
}
}
// at this point values_out contains all second elements from values_in tuples whose
// first is less than 5
}
void function(const std::vector<std::pair<int,int>> &pairs,
std::vector<int> &output) {
/* ... */
}