using lambda expression and find_if on a collection - c++

I have a container object :
R Container;
R is of type list<T*> or vector<T*>
I am trying to write the following function:
template<typename T, typename R>
T& tContainer_t<T, R>::Find( T const item ) const
{
typename R::const_iterator it = std::find_if(Container.begin(), Container.end(), [item](const R&v) { return item == v; });
if (it != Container.end())
return (**it);
else
throw Exception("Item not found in container");
}
When trying the method (v is an object of my class)
double f = 1.1;
v.Find(f);
I get binary '==' : no operator found which takes a left-hand operand of type 'const double' (or there is no acceptable conversion)
I am confused with the lambda expression syntax and what i should write there and couldn't find any friendly explanation.
What is wrong ? 10x.

Missing a bit of context, but I note:
You return **it so you possibly want to compare *v==itemt
You pass const R&v where I suspect you meant const T&v into the lambda
You used a const_iterator, but returned a non-const reference. That was a mismatch
I made some params const& for efficiency (and to support non-copyable/non-movable types)
Here is working code, stripped of the missing class references:
#include <vector>
#include <algorithm>
#include <iostream>
template<typename T, typename R=std::vector<T> >
T& Find(R& Container, T const& item )
{
typename R::iterator it = std::find_if(Container.begin(), Container.end(), [&item](const T&v) { return item == v; });
if (it != Container.end())
return *it;
else
throw "TODO implement";
}
int main(int argc, const char *argv[])
{
std::vector<double> v { 0, 1, 2, 3 };
Find(v, 2.0); // not '2', but '2.0' !
return 0;
}

Related

Using std::ranges algorithms with custom containers and iterators

I have the following simplified code representing a range of integers that I want to use with various std algorithms. I am trying to update my code to use C++20's ranges versions of the algorithms so I can delete all of the begin() and end() calls. In the below code, std::any_of works with my container and iterator, but std::ranges::any_of does not.
#include <iostream>
#include <algorithm>
class Number_Iterator {
public:
using iterator_category = std::input_iterator_tag;
using value_type = int;
using difference_type = int;
using pointer = int*;
using reference = int&;
Number_Iterator(int start) noexcept : value(start) {}
Number_Iterator& operator++() noexcept { ++value; return *this; }
bool operator==(const Number_Iterator& other) const noexcept = default;
int operator*() const noexcept { return value; }
private:
int value;
};
class Numbers {
public:
Numbers(int begin, int end) noexcept : begin_value(begin), end_value(end) {}
Number_Iterator begin() const noexcept { return {begin_value}; }
Number_Iterator end() const noexcept { return {end_value}; }
private:
int begin_value;
int end_value;
};
int main() {
const auto set = Numbers(1, 10);
const auto multiple_of_three = [](const auto n) { return n % 3 == 0; };
// Compiles and runs correctly
if(std::any_of(set.begin(), set.end(), multiple_of_three)) {
std::cout << "Contains multiple of three.\n";
}
// Does not compile
if(std::ranges::any_of(set, multiple_of_three)) {
std::cout << "Contains multiple of three.\n";
}
return 0;
}
When I try to compile the above code, I get the following error messages from Visual Studio 2019 (16.11.15) with the flag /std:c++20:
Source.cpp(42,21): error C2672: 'operator __surrogate_func': no matching overloaded function found
Source.cpp(42,7): error C7602: 'std::ranges::_Any_of_fn::operator ()': the associated constraints are not satisfied
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\include\algorithm(1191): message : see declaration of 'std::ranges::_Any_of_fn::operator ()'
I have tried looking at the std::ranges::_Any_of_fn::operator() declaration, but I find myself more confused by that.
What am I missing to get the std::ranges algorithms to work with my container?
For the curious, what I'm actually iterating over are squares on a chess board, but those are represented by integers, so the difference from the above code isn't so great.
To use your range with any_of it must satisfy the input_range concept:
template< class T >
concept input_range =
ranges::range<T> && std::input_iterator<ranges::iterator_t<T>>;
Then via the input_iterator concept:
template<class I>
concept input_iterator =
std::input_or_output_iterator<I> &&
std::indirectly_readable<I> &&
requires { typename /*ITER_CONCEPT*/<I>; } &&
std::derived_from</*ITER_CONCEPT*/<I>, std::input_iterator_tag>;
and via the input_or_output_iterator concept
template <class I>
concept input_or_output_iterator =
requires(I i) {
{ *i } -> /*can-reference*/;
} &&
std::weakly_incrementable<I>;
you land in the weakly_incrementable concept:
template<class I>
concept weakly_incrementable =
std::movable<I> &&
requires(I i) {
typename std::iter_difference_t<I>;
requires /*is-signed-integer-like*/<std::iter_difference_t<I>>;
{ ++i } -> std::same_as<I&>; // pre-increment
i++; // post-increment
};
in which you see that the iterator must have both the pre-increment and post-increment versions of operator++.
The iterator must also be default constructible because std::ranges::end creates a sentinel:
template< class T >
requires /* ... */
constexpr std::sentinel_for<ranges::iterator_t<T>> auto end( T&& t );
And sentinel_for
template<class S, class I>
concept sentinel_for =
std::semiregular<S> &&
std::input_or_output_iterator<I> &&
__WeaklyEqualityComparableWith<S, I>;
requires it to satisfy semiregular:
template <class T>
concept semiregular = std::copyable<T> && std::default_initializable<T>;
But without being default constructible, this substitution will fail:
template < class T >
concept default_initializable = std::constructible_from<T> && requires { T{}; } && ...
Apparently, the std::ranges algorithms require two more methods in the iterator: a default constructor and a post-increment operator (return value optional). Adding these methods allows the code to compile and run correctly:
Number_Iterator() noexcept : value(-1) {}
void operator++(int) noexcept { ++value; }

How can i get template's type if my instance is stl map?

I want a get_value template function.
please see the following code:
template<typename T>
(something i want) get_value(const T& m, int key) {
auto it = m.upper_bound(key);
return it == m.begin() ? (*it).second : (*--it).second; // please notice here,
// if my instance is map<int, map<string, int>> the return type should be m.second's type
// that's map<string, int>
}
int main() {
std::map<int, std::map<std::string, int>> m;
auto& it = get_value(m, 10);
}
as you can see, the template function should have a return type, which is depend on instance's second type, is there any method i can get this type to make the code runnable?
The "second type" in a std::map<K,V> is called std::map<K,V>::mapped_type. However, you can use auto to let the compiler deduce that for you:
template<typename T>
auto get_value(const T& m, int key) {
auto it = m.upper_bound(key);
return it == m.begin() ? (*it).second : (*--it).second; // please notice here,
}
or with explicit type:
template<typename T>
typename T::mapped_type get_value(const T& m, int key) {
auto it = m.upper_bound(key);
return it == m.begin() ? (*it).second : (*--it).second; // please notice here,
}
If you can use C++14 standard or above, the safest way to go would be to use decltype(auto) as the return type:
template<typename T>
decltype(auto) get_value(const T& m, int key);
The difference to a plain auto is that decltype(auto) preserves cv-qualifiers, and in your case you most likely want to forward exactly the same type that std::map gives you.
For example, since the actual code uses std::map<int, std::map<std::string, int>>, you might want to avoid copying the return value every time, and decltype(auto) will achieve that.

Function to find duplicate values after applying a function

I'd like a function in C++ which finds an item in a collection which has the same value of function(key) as another item in the collection.
e.g.
std::set<int> ints = {1, -1, 3};
// Finds an item in the set with the same absolute value as
// another item.
int* dupe = find_duplicates(ints, [](int x) { return std::abs(x); });
// Should print -1 or 1
if (dupe != 0) std::cout << "Found dupe: " << *dupe << std::endl;
However, I'm having trouble even writing the function signature for this method.
In Java it'd be something like static Integer findDuplicates<T, U>(Iterable<T>, Function<T, U> func).
In C++ I've got as far as the following, but it doesn't compile:
template<template <typename T> Collection, typename U>
T* find_duplicates(
const Collection<T>& collection,
const std::function<U(T)>& func) { ... }
The error I get is error: 'T' does not name a type.
Any pointers? (I'd also be interested in a way to get around the use of the "raw" pointer to T*, but that's probably better for a separate question)
In your example, T is unrecognizable and virtually useless. You should introduce the type T earlier and then use it to specify the Collection, like so:
template<typename T, template <typename> typename Collection, typename U>
T* find_duplicates(const Collection<T>& collection,
const std::function<U(T)>& func)
{
// some logic here
}
Also: notice that you missed a single typename before the Collection, as I pointed out in a comment previously. The above example is adjusted for that suggestion.
For your specific example, something like this should work,
#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
int main() {
std::set<int> ints = {1, -1, 3};
auto dupe = std::find_if(ints.begin(),ints.end(),[&](const int& first){
return std::find_if(ints.begin(),ints.end(),[&](const int& second) {
// so a the same value isn't checked against itself..
if (&first == &second) return false;
return std::abs(first) == std::abs(second);
}) != ints.end();
} );
if (dupe != ints.end()) std::cout << "Found dupe: " << *dupe << std::endl;
}
Demo
Don't be so picky about your function parameter types. You don't really need collection to be a class template specialization, just something you can iterate over (which could even be a C-style array). func just needs to be invokable, and forcing it to be a std::function object can be less efficient than directly using a function pointer or lambda, because of the type erasure std::function adds and then resolves.
So a working declaration could be
template <typename Collection, typename Func>
auto find_duplicates(Collection& collection, const Func& func)
-> typename std::iterator_traits<decltype(std::begin(collection))>::value_type*;
I would do:
#include <utility>
#include <iterator>
#include <set>
// Calling with an rvalue collection would be bad news.
template <typename Collection, typename Func>
void find_duplicates(Collection&&, const Func&) = delete;
template <typename Collection, typename Func>
auto find_duplicates(Collection& collection, const Func& func)
-> typename std::iterator_traits<decltype(std::begin(collection))>::value_type*
{
auto iter = std::begin(collection);
using value_type = typename std::iterator_traits<decltype(iter)>::value_type;
auto ptr_compare = [&func](value_type* p, value_type* q)
{ return func(*p) < func(*q); };
std::set<value_type*, decltype(ptr_compare)> iter_set{ptr_compare};
for (; iter != std::end(collection); ++iter) {
auto insert_result = iter_set.insert(std::addressof(*iter));
if (!insert_result.second)
return *insert_result.first;
}
return nullptr;
}
Sometimes a raw pointer really is the answer. It implies the value might be null, and that the pointer has no ownership relation to the object. In this case, not using the pointer after it's invalidated by modifying or destroying the container is up to the caller, but it has the usual pointer-to-container-element invalidation semantics which depend on the container details.
This won't work with std::vector<bool> or any other pseudo-container where *collection.begin() has a "proxy" type. If you want to support those and can use C++17 std::optional or boost::optional, you could return an optional<value_type> instead of a raw pointer, though this will make a copy of the returned duplicated value. If you can't use those or a copy is undesirable, maybe write a template class iter_or_null<InputIter> that contains an iterator, has operator* and operator-> that just call the iterator's operators, and satisfies the NullablePointer concept.
You're actually being too restrictive with your template. You want your template to take any container for which std::begin and std::end are defined, and any function object that can accept an instance of whatever the container contains. In the template world, you just accept any type, use it the way you would like to, and if the caller doesn't provide a compatibly-typed object, they will get a compilation error.
Further, there's no need to use std::function - it will end up potentially allocating memory when you can just accept the function object as a parameter with a deduced type.
With C++14, auto-deduced return types and auto parameters to lambdas allow you to write very generic code. Here's my solution. It returns an iterator into the container pointing to the first duplicate found, or std::end(c) if no duplicate is found.
#include <algorithm>
#include <cmath>
#include <iterator>
#include <iostream>
#include <set>
template<typename C, typename F>
auto find_duplicates(const C & c, const F & func)
{
return std::find_if(std::begin(c), std::end(c), [&](const auto & first) {
return std::any_of(std::begin(c), std::end(c), [&](const auto & second) {
return &first != &second && func(first) == func(second);
});
});
}
int main()
{
std::set<int> s{1, 3, -1};
auto const iter = find_duplicates(s, [](int x) { return std::abs(x); });
if (iter != std::end(s))
{
std::cout << "Duplicate found: " << *iter << '\n';
}
}
EDIT: I just noticed you specified the C++11 tag. It's only a little more complicated in C++11:
template<typename C, typename F>
auto find_duplicates(const C & c, const F & func) -> decltype(std::begin(c))
{
using ContainedType = decltype(*std::begin(c));
return std::find_if(std::begin(c), std::end(c), [&](const ContainedType & first) {
return std::any_of(std::begin(c), std::end(c), [&](const ContainedType & second) {
return &first != &second && func(first) == func(second);
});
});
}

How to deduce the return type of a std::bind object for template use?

I have a class which basically just manages a vector of custom types. To relieve me from writing the same iteration loop over and over again I wrote the following construct:
template<typename T>
uint64_t ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> vec, T method)
{
return std::accumulate(vec.begin(), vec.end(), 0, [&](uint64_t acc, const MyClass* c)
{
return acc + (c ? method(c) : 0);
});
}
which is then called like this:
ACCUMULATE_ON_VECTOR(_myVec, std::bind(&MyClass::someMethod, std::placeholders::_1));
This works very well in concept but since I have a lot of methods returning different integer types (signed/unsigned, signed/unsigned long), I'd like to abstract away the for now hardcoded uint64_t cause I get compiler warnings all over the place. For this I somehow need to get the return type of the bind object. Can I somehow do this with decltype? What I'm looking for is this:
template<typename T>
<new deduced type> ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> vec, T method)
{
return std::accumulate(vec.begin(), vec.end(), 0, [&](<new deduced type> acc, const MyClass* c)
{
return acc + (c ? method(c) : 0);
});
}
You can do this using std::result_of:
template<typename Func>
typename std::result_of<Func(MyClass*)>::type
ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> &vec, Func method)
{
using ResultType = typename std::result_of<Func(MyClass*)>::type;
return std::accumulate(vec.begin(), vec.end(), ResultType{},
[&](typename std::result_of<Func(MyClass*)>::type acc,
const MyClass* c)
{
return acc + (c ? method(c) : ResultType{});
});
}
Note I'm value-initializing the return type instead of using the integer literal zero.
It might be more readable to wrap the function parameter in a std::function<ResultT(MyClass*)>: the accumulate function would be directly templated on the result type, pushing responsibility for that up to the call site.
BTW, you don't need the auto/trailing return type technique here, because the return type doesn't depend on the argument list, only on the template parameter - nevertheless, I think it looks slightly nicer:
template<typename Func>
auto ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> &vec,
Func method)
-> typename std::result_of<Func(MyClass*)>::type
{
std::bind has a member type called result_type which is
1) If F is a pointer to function or a pointer to member function, result_type is the return type of F. If F is a class type with nested typedef result_type, then result_type is F::result_type. Otherwise no result_type is defined.
2) result_type is exactly R.
We can use a trailing return type like
template<typename T>
auto ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> vec, T method) -> typename T::result_type
{
typename T::result_type begin = 0;
return std::accumulate(vec.begin(), vec.end(), begin, [&](typename T::result_type acc, const MyClass* c)
{
return acc + (c ? method(c) : 0);
});
}
This will work with C++11 and above.
I also added typename T::result_type begin = 0; to the function so the type passed to accumulate is the same type as the return of the function. As you just had 0 that gets deduced to an int and accumulate will always return an int.
The result type of accumulate has nothing to do with the passed accumulating function. The result type of accumulate is the type of the third parameter. You're getting warnings because your third parameter is 0 (which is int) so the int64 will get truncated to int anyway! You should pass int46(0) as your third parameter for a warning-free code.
You could use std::iterator_traits
template<typename T>
auto ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> vec, T method)
-> typename std::iterator_traits<T(MyClass*)>::value_type
{
return std::accumulate(
vec.begin(),
vec.end(),
0,
[&](typename std::iterator_traits<T(MyClass*)>::value_type acc, const MyClass* c)
{
return acc + (c ? method(c) : 0);
}
);
}
If using C++14 is ok you can just substitute your mystery type for auto.
If you're limited to C++11 you can use the following slightly uglier solution:
template<typename T>
auto ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> vec, T method) ->
typename std::result_of<decltype(method)(MyClass*)>::type
{
return std::accumulate(vec.begin(), vec.end(), 0,
[&](typename std::result_of<decltype(method)(MyClass*)>::type acc, const MyClass* c)
{
return acc + (c ? method(c) : 0);
});
}
This gives you the type that the result of a call to method on a MyClass* would have.
By the way, there's really no need to use bind at the call site. You could achieve the same thing using a lambda:
ACCUMULATE_ON_VECTOR(_myVec, [] (const MyClass* p) { return p->someMethod(); });
(In C++14 you could replace const MyClass* with auto if you wanted to)

C++: select argmax over vector of classes w.r.t. arbitrary expression

I have trouble describing my problem so I'll give an example:
I have a class description that has a couple of variables in it, for example:
class A{
float a, b, c, d;
}
Now, I maintain a vector<A> that contains many of these classes. What I need to do very very often is to find the object inside this vector that satisfies that one of it's parameters is maximal w.r.t to the others. i.e code looks something like:
int maxi=-1;
float maxa=-1000;
for(int i=0;i<vec.size();i++){
res= vec[i].a;
if(res > maxa) {
maxa= res;
maxi=i;
}
}
return vec[maxi];
However, sometimes I need to find class with maximal a, sometimes with maximal b, sometimes the class with maximal 0.8*a + 0.2*b, sometimes I want a maximal a*VAR + b, where VAR is some variable that is assigned in front, etc. In other words, I need to evaluate an expression for every class, and take the max. I find myself copy-pasting this everywhere, and only changing the single line that defines res.
Is there some nice way to avoid this insanity in C++? What's the neatest way to handle this?
Thank you!
I know this thread is old, but i find it quite useful to implement a powerful argmax function in C++.
However, as far as i can see, all the given examples above rely on std::max_element, which does comparison between the elements (either using a functor or by calling the operator<). this can be slow, if the calculation for each element is expensive. It works well for sorting numbers and handling simple classes, but what if the functor is much more complex? Maybe calculating a heuristic value of a chess position or something else that generate a huge tree etc.
A real argmax, as the thread starter mentioned, would only calculate its arg once, then save it to be compared with the others.
EDIT: Ok i got annoyed and had too much free time, so i created one < C++11 and one C++11 version with r-value references, first the C++11 version:
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
template<typename IteratorT, typename HeuristicFunctorT>
IteratorT argmax(IteratorT && it, const IteratorT & end, const HeuristicFunctorT & functor) {
IteratorT best(it++);
typename HeuristicFunctorT::result_type best_value(functor(*best));
for(; it != end; ++it) {
typename HeuristicFunctorT::result_type value(functor(*it));
if (value > best_value) {
best_value = value;
best = it;
}
}
return best;
}
template<typename IteratorT, typename HeuristicFunctorT>
inline IteratorT argmax(const IteratorT & begin, const IteratorT & end, const HeuristicFunctorT & functor) {
return argmax(IteratorT(begin), end, functor);
}
class IntPairFunctor : public std::unary_function< std::pair<int, int>, int > {
public:
int operator() (const std::pair<int, int> & v) const {
return v.first + v.second;
}
};
std::pair<int, int> rand_pair() {
return std::make_pair(rand(), rand());
}
int main(int argc, const char **argv) {
srand(time(NULL));
std::vector< std::pair<int, int> > ints;
std::generate_n(std::back_insert_iterator< std::vector< std::pair<int, int> > >(ints), 1000, rand_pair);
std::vector< std::pair<int, int> >::iterator m (argmax(ints.begin(), ints.end(), IntPairFunctor()));
std::cout << std::endl << "argmax: " << *m << std::endl;
}
The non C++11 version is much simpler, only the template:
template<typename IteratorT, typename HeuristicFunctorT>
IteratorT argmax(IteratorT it, const IteratorT & end, const HeuristicFunctorT & functor) {
IteratorT best(it++);
typename HeuristicFunctorT::result_type best_value(functor(*best));
for(; it != end; ++it) {
typename HeuristicFunctorT::result_type value(functor(*it));
if (value > best_value) {
best_value = value;
best = it;
}
}
return best;
}
Note that neither version requires any template arguments, the only requirement is that the heuristic implements the unary_function class
template <typename F>
struct CompareBy
{
bool operator()(const typename F::argument_type& x,
const typename F::argument_type& y)
{ return f(x) < f(y); }
CompareBy(const F& f) : f(f) {}
private:
F f;
};
template <typename T, typename U>
struct Member : std::unary_function<U, T>
{
Member(T U::*ptr) : ptr(ptr) {}
const T& operator()(const U& x) { return x.*ptr; }
private:
T U::*ptr;
};
template <typename F>
CompareBy<F> by(const F& f) { return CompareBy<F>(f); }
template <typename T, typename U>
Member<T, U> mem_ptr(T U::*ptr) { return Member<T, U>(ptr); }
You need to include <functional> for this to work. Now use, from header <algorithm>
std::max_element(v.begin(), v.end(), by(mem_ptr(&A::a)));
or
double combination(A x) { return 0.2 * x.a + 0.8 * x.b; }
and
std::max_element(v.begin(), v.end(), by(std::fun_ptr(combination)));
or even
struct combination : std::unary_function<A, double>
{
combination(double x, double y) : x(x), y(y) {}
double operator()(const A& u) { return x * u.a + y * u.b; }
private:
double x, y;
};
with
std::max_element(v.begin(), v.end(), by(combination(0.2, 0.8)));
to compare by a member or by linear combinations of a and b members. I split the comparer in two because the mem_ptr thing is damn useful and worth being reused. The return value of std::max_element is an iterator to the maximum value. You can dereference it to get the max element, or you can use std::distance(v.begin(), i) to find the corresponding index (include <iterator> first).
See http://codepad.org/XQTx0vql for the complete code.
This is what functors and STL are made for:
// A class whose objects perform custom comparisons
class my_comparator
{
public:
explicit my_comparator(float c1, float c2) : c1(c1), c2(c2) {}
// std::max_element calls this on pairs of elements
bool operator() (const A &x, const A &y) const
{
return (x.a*c1 + x.b*c2) < (y.a*c1 + y.b*c2);
}
private:
const float c1, c2;
};
// Returns the "max" element in vec
*std::max_element(vec.begin(), vec.end(), my_comparator(0.8,0.2));
Is the expression always linear? You could pass in an array of four coefficients. If you need to support arbitrary expressions, you'll need a functor, but if it's just an affine combination of the four fields then there's no need for all that complexity.
You can use the std::max_element algorithm with a custom comparator.
It's easy to write the comparator if your compiler supports lambda expressions.
If it doesn't, you can write a custom comparator functor. For the simple case of just comparing a single member, you can write a generic "member comparator" function object, which would look something like this:
template <typename MemberPointer>
struct member_comparator
{
MemberPointer p_;
member_comparator(MemberPointer p) : p_(p) { }
template <typename T>
bool operator()(const T& lhs, const T& rhs) const
{
return lhs.*p_ < rhs.*p_;
}
};
template <typename MemberPointer>
member_comparator<MemberPointer> make_member_comparator(MemberPointer p)
{
return member_comparator<MemberPointer>(p);
}
used as:
// returns an iterator to the element that has the maximum 'd' member:
std::max_element(v.begin(), v.end(), make_member_comparator(&A::d));
You could use the std::max_element STL algorithm providing a custom comparison predicate each time.
With C++0x you can even use a lambda function for it for maximum conciseness:
auto maxElement=*std::max_element(vector.begin(), vector.end(), [](const A& Left, const A& Right) {
return (0.8*Left.a + 0.2*Left.b)<(0.8*Right.a + 0.2*Right.b);
});
Sample of using max_element/min_element with custom functor
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
struct A{
float a, b, c, d;
};
struct CompareA {
bool operator()(A const & Left, A const & Right) const {
return Left.a < Right.a;
}
};
int main() {
vector<A> vec;
vec.resize(3);
vec[0].a = 1;
vec[1].a = 2;
vec[2].a = 1.5;
vector<A>::iterator it = std::max_element(vec.begin(), vec.end(), CompareA());
cout << "Largest A: " << it->a << endl;
it = std::min_element(vec.begin(), vec.end(), CompareA());
cout << "Smallest A: " << it->a << endl;
}