Ways of defining accepted template parameter values - c++

My program has a series of functions that take a template argument for an integer that needs to be known at compile time. The functions only accept a few possible values for this integer, and I am looking for a clean way to have a single place defining these options so the list can easily added or changed. Here is an example of how I am currently doing this.
template<int Dim>
float computeMinDist(float* data, int idx);
float computeMinDistSelect(float* data, int idx, int dim) {
if(dim <= 64) {
return computeMinDist<64>(data, idx);
}
else if(dim <= 100) {
return computeMinDist<100>(data, idx);
}
else {
printf("Dimension over 100 not supported.\n");
exit(1);
}
}
I have other functions that have the selected dimension parameter, and I would like to be able to define all of the options in one place. I've tried using a static constexpr arrays or enums to store the options, but can't get it to compile. Any advice would be great! Thanks.

You could create a table at compile time and binary search it for the specific value you get at runtime:
using table_pair = std::pair<int, float(*)(float*, int)>;
template <int... Dims>
constexpr auto make_table() {
auto arr = std::array<table_pair, sizeof...(Dims)>
{
table_pair{Dims, &computeMinDist<Dims>}...
};
// Can get rid of this sort if you can guarantee you always pass ordered Dims
std::sort(arr.begin(), arr.end(), [](auto& l, auto& r) {
return l.first < r.first;
});
return arr;
}
// Here you define all possible options.
constexpr auto table = make_table<64, 100>();
float computeMinDistSelect(float* data, int idx, int dim) {
auto it = std::lower_bound(
table.begin(), table.end(),
table_pair{dim, nullptr},
[](auto& l, auto& r) { return l.first < r.first; });
if (it == table.end()) {
printf("Dimension %d not supported.\n", dim);
exit(1);
}
return it->second(data, idx);
}
I return an array that we binary search since I assume your values seem to be pretty sparse. If your possible values are pretty dense, you can just return an array of function pointers with the invalid values having nullptr and index into the table directly.
https://godbolt.org/z/Yce355bP4

Related

Can I use std::accumulate with a fallible operation without exceptions?

I have some operation that I would like to use with std::accumulate, but it may fail for some elements, in which case the accumulation should be aborted. With exceptions, I could throw an exception in case of failure, but I need to build without exceptions. With exceptions, this would look like this (the operation being greatly simplified):
std::optional<int> sum_accumulate_with_exceptions(
std::vector<int> const& aVec) {
try {
return std::accumulate(aVec.begin(), aVec.end(), 0,
[](int oldSum, int current) {
if (current > 42)
throw std::logic_error{"too large"};
return oldSum + current;
});
} catch (std::logic_error const&) {
return std::nullopt;
}
}
Actually, even with the possibility of using exceptions, this appears quite wasteful, as I am not interested in the particular exception thrown, and so the overhead of exceptions is unnecessarily large.
Using std::accumulate, I could use an error flag like this:
std::optional<int> sum_accumulate_without_exceptions(
std::vector<int> const& aVec) {
bool errored = false;
int res = std::accumulate(aVec.begin(), aVec.end(), 0,
[&errored](int oldSum, int current) {
if (errored) return 0;
if (current > 42) {
errored = true;
return 0;
}
return oldSum + current;
});
return errored ? std::optional<int>{} : res;
}
However, this is clearly bad, since this always iterates over the whole container, which might be large.
I came up with my own variant of std::accumulate:
template <typename It, typename T, typename Op>
std::optional<T> accumulate_shortcircuit(It aBegin, It aEnd, T aInit,
const Op& aOp) {
std::optional<T> res = std::move(aInit);
for (auto it = aBegin; it != aEnd; ++it) {
res = aOp(*res, *it);
if (!res) break;
}
return res;
}
This can be used nicely for the example case like this:
std::optional<int> sum_accumulate_shortcircuit(std::vector<int> const& aVec) {
return accumulate_shortcircuit(aVec.begin(), aVec.end(), 0,
[](int oldSum, int current) {
if (current > 42) {
return std::optional<int>{};
}
return std::optional<int>{oldSum + current};
});
}
However, I would prefer using std::accumulate (or any other standard library algorithm [edit:] or combination of them) itself, instead of using a replacement. Is there any way to achieve this?
While I was using C++17's std::optional in the example, ideally this would only use C++14 standard library algorithms, but I am also interested in solutions from newer/future standard versions.
[edit:] Based on #NathanOliver's answer, accumulate_shortcircuit could be implemented like this without having the range TS:
template <typename It, typename T, typename Op>
std::optional<T> accumulate_shortcircuit(It aBegin, It aEnd, T aInit,
const Op& aOp) {
std::optional<T> res = std::move(aInit);
std::all_of(aBegin, aEnd, [&](const T& element) {
return static_cast<bool>(res = aOp(*res, element));
});
return res;
}
You need an algorithm that has short circuiting built in. The first one that comes to to mind is std::any_of. You can use a lambda to do the sumation, and then return true to it once you've reached the point where you want to return. That would give you a function like
int sum_accumulate_shortcircuit(std::vector<int> const& aVec)
{
int sum = 0;
std::any_of(aVec.begin(), aVec.end(),
[&](auto elm) { if (elm > 42) return true; sum += elm; return false; });
return sum;
}
For future reference, this type of composition of algorithms/operations will be much easier in C++20 (with the inclusion of the ranges TS). This is an example from the current TS using accumulate and view::take_while:
auto sum = ranges::accumulate(my_vec | view::take_while([] (auto i) -> i <= 42), 0);

Get all objects with a specific member value from a list of objects

From a vector
std::vector<S> structures;
containing structures of the type
struct S {
double x;
double y;
double weight;
};
I want to repeatedly get all the structs with a specific weight, i.e. I want to execute the following pseudocode:
do 1000 times:
weight = GetASpecificWeight()
MatchingStructures = structures.GetAllStructuresWithWeight(weight)
To do this efficiently, I want to sort the structuresvector and do a binary search in each iteration.
How can I implement this using std:: code?
Sorting the vector can be done using std::sort and finding the range of elements that have the specified weight can be done with std::equal_range.
However, as Daniel pointed out in the comment, it is likely that getASpecificWeight() returns a double and not a Structure, so in order to call equal_range we either need to create a dummy Structure or a function object that compares doubles to Structures with the desired semantics. A single lambda doesn't work because the binary search needs to be able to compare Structures to weights both ways.
Alternative 1: Using a dummy Structure
So first, lets create a dummy Structure, since this is less code.
In total, it might look something like this
auto sort_structure_by_weight_asc = [](Structure const& s1, Structure const& s2) {
return s1.weight < s2.weight;
};
std::sort(structures.begin(), structures.end(),
sort_structure_by_weight_asc);
for (auto i = 0; i < 1000; ++i) {
auto weight = GetASpecificWeight();
auto const dummy_structure = Strucutre{0.0, 0.0, weight};
auto range = std::equal_range(structures.cbegin(), structures.cend(),
dummy_structure, sort_structure_by_weight_asc);
if (range.first != structures.cend() && range.second != structures.cbegin()) {
// do whatever you want here
// if the `if`-condition isn't satisfied, no structure
// had weight `weight`.
}
}
If you need to modify the elements in the structures vector, you can replace cbegin and cend in the call to std::equal_range and the if-condition by begin/end respectively.
Alternative 2: Handcrafted function object
However, I personally don't think creating the dummy struct is very clean, so lets see how a custom function object would improve the code.
The function object itself can be defined as
struct ComparatorStructureToWeightAsc {
bool operator()(Structure const& s, double weight) const {
return s.weight < weight;
}
bool operator()(double weight, Structure const& s) const {
return weight < s.weight;
}
};
Then the code would look like this:
std::sort(structures.begin(), structures.end(),
[](auto const& s1, auto const& s2) { return s1.weight < s2.weight; });
for (auto i = 0; i < 1000; ++i) {
auto weight = GetASpecificWeight();
auto range = std::equal_range(structures.cbegin(), structures.cend(),
weight, ComparatorStructureToWeightAsc);
if (range.first != structures.cend() && range.second != structures.cbegin()) {
// do whatever you want here
// if the `if`-condition isn't satisfied, no structure
// had weight `weight`.
}
}
Alternative 3: Using Boost.Functional/OverloadedFunction
As you can see I'm bad at naming things, so having to name the function object used to compare Structures to weights is kind of awkward, in particular if it only used in this single place. If you have access to Boost, in particular to Boost.Functional/OverloadedFunction, you can use two lambdas instead of the handcrafted function object.
The code then looks like this:
std::sort(structures.begin(), structures.end(),
[](auto const& s1, auto const& s2) { return s1.weight < s2.weight; });
for (auto i = 0; i < 1000; ++i) {
auto weight = GetASpecificWeight();
auto range = std::equal_range(structures.cbegin(), structures.cend(), weight,
boost::make_overloaded_function(
[](Structure const& s, double weight) { return s.weight < weight; },
[](double weight, Structure const& s) { return weight < s.weight; }));
if (range.first != structures.cend() && range.second != structures.cbegin()) {
// do whatever you want here
// if the `if`-condition isn't satisfied, no structure
// had weight `weight`.
}
}

C++ Bimap Left unordered_map Right sorted mutable multimap

I need to implement the following datastructure for my project. I have a relation of
const MyClass*
to
uint64_t
For every pointer I want to save a counter connected to it, which can be changed over time (in fact only incremented). This would be no problem, I could simply store it in a std::map. The problem is that I need fast access to the pointers which have the highest values.
That is why I came to the conclusion to use a boost::bimap. It is defined is follows for my project:
typedef boost::bimaps::bimap<
boost::bimaps::unordered_set_of< const MyClass* >,
boost::bimaps::multiset_of< uint64_t, std::greater<uint64_t> >
> MyBimap;
MyBimap bimap;
This would work fine, but am I right that I can not modify the uint64_t on pair which were inserted once? The documentation says that multiset_of is constant and therefore I cannot change a value of pair in the bimap.
What can I do? What would be the correct way to change the value of one key in this bimap? Or is there a simpler data structure possible for this problem?
Here's a simple hand-made solution.
Internally it keeps a map to store the counts indexed by object pointer, and a further multi-set of iterators, ordered by descending count of their pointees.
Whenever you modify a count, you must re-index. I have done this piecemeal, but you could do it as a batch update, depending on requirements.
Note that in c++17 there is a proposed splice operation for sets and maps, which would make the re-indexing extremely fast.
#include <map>
#include <set>
#include <vector>
struct MyClass { };
struct store
{
std::uint64_t add_value(MyClass* p, std::uint64_t count = 0)
{
add_index(_map.emplace(p, count).first);
return count;
}
std::uint64_t increment(MyClass* p)
{
auto it = _map.find(p);
if (it == std::end(_map)) {
// in this case, we'll create one - we could throw instead
return add_value(p, 1);
}
else {
remove_index(it);
++it->second;
add_index(it);
return it->second;
}
}
std::uint64_t query(MyClass* p) const {
auto it = _map.find(p);
if (it == std::end(_map)) {
// in this case, we'll create one - we could throw instead
return 0;
}
else {
return it->second;
}
}
std::vector<std::pair<MyClass*, std::uint64_t>> top_n(std::size_t n)
{
std::vector<std::pair<MyClass*, std::uint64_t>> result;
result.reserve(n);
for (auto idx = _value_index.begin(), idx_end = _value_index.end() ;
n && idx != idx_end ;
++idx, --n) {
result.emplace_back((*idx)->first, (*idx)->second);
}
return result;
}
private:
using map_type = std::map<MyClass*, std::uint64_t>;
struct by_count
{
bool operator()(map_type::const_iterator l, map_type::const_iterator r) const {
// note: greater than orders by descending count
return l->second > r->second;
}
};
using value_index_type = std::multiset<map_type::iterator, by_count>;
void add_index(map_type::iterator iter)
{
_value_index.emplace(iter->second, iter);
}
void remove_index(map_type::iterator iter)
{
for(auto range = _value_index.equal_range(iter);
range.first != range.second;
++range.first)
{
if (*range.first == iter) {
_value_index.erase(range.first);
return;
}
}
}
map_type _map;
value_index_type _value_index;
};

Sorting one std::vector based on the content of another [duplicate]

This question already has answers here:
How can I sort two vectors in the same way, with criteria that uses only one of the vectors?
(9 answers)
Closed 9 months ago.
I have several std::vector, all of the same length. I want to sort one of these vectors, and apply the same transformation to all of the other vectors. Is there a neat way of doing this? (preferably using the STL or Boost)? Some of the vectors hold ints and some of them std::strings.
Pseudo code:
std::vector<int> Index = { 3, 1, 2 };
std::vector<std::string> Values = { "Third", "First", "Second" };
Transformation = sort(Index);
Index is now { 1, 2, 3};
... magic happens as Transformation is applied to Values ...
Values are now { "First", "Second", "Third" };
friol's approach is good when coupled with yours. First, build a vector consisting of the numbers 1…n, along with the elements from the vector dictating the sorting order:
typedef vector<int>::const_iterator myiter;
vector<pair<size_t, myiter> > order(Index.size());
size_t n = 0;
for (myiter it = Index.begin(); it != Index.end(); ++it, ++n)
order[n] = make_pair(n, it);
Now you can sort this array using a custom sorter:
struct ordering {
bool operator ()(pair<size_t, myiter> const& a, pair<size_t, myiter> const& b) {
return *(a.second) < *(b.second);
}
};
sort(order.begin(), order.end(), ordering());
Now you've captured the order of rearrangement inside order (more precisely, in the first component of the items). You can now use this ordering to sort your other vectors. There's probably a very clever in-place variant running in the same time, but until someone else comes up with it, here's one variant that isn't in-place. It uses order as a look-up table for the new index of each element.
template <typename T>
vector<T> sort_from_ref(
vector<T> const& in,
vector<pair<size_t, myiter> > const& reference
) {
vector<T> ret(in.size());
size_t const size = in.size();
for (size_t i = 0; i < size; ++i)
ret[i] = in[reference[i].first];
return ret;
}
typedef std::vector<int> int_vec_t;
typedef std::vector<std::string> str_vec_t;
typedef std::vector<size_t> index_vec_t;
class SequenceGen {
public:
SequenceGen (int start = 0) : current(start) { }
int operator() () { return current++; }
private:
int current;
};
class Comp{
int_vec_t& _v;
public:
Comp(int_vec_t& v) : _v(v) {}
bool operator()(size_t i, size_t j){
return _v[i] < _v[j];
}
};
index_vec_t indices(3);
std::generate(indices.begin(), indices.end(), SequenceGen(0));
//indices are {0, 1, 2}
int_vec_t Index = { 3, 1, 2 };
str_vec_t Values = { "Third", "First", "Second" };
std::sort(indices.begin(), indices.end(), Comp(Index));
//now indices are {1,2,0}
Now you can use the "indices" vector to index into "Values" vector.
Put your values in a Boost Multi-Index container then iterate over to read the values in the order you want. You can even copy them to another vector if you want to.
Only one rough solution comes to my mind: create a vector that is the sum of all other vectors (a vector of structures, like {3,Third,...},{1,First,...}) then sort this vector by the first field, and then split the structures again.
Probably there is a better solution inside Boost or using the standard library.
You can probably define a custom "facade" iterator that does what you need here. It would store iterators to all your vectors or alternatively derive the iterators for all but the first vector from the offset of the first. The tricky part is what that iterator dereferences to: think of something like boost::tuple and make clever use of boost::tie. (If you wanna extend on this idea, you can build these iterator types recursively using templates but you probably never want to write down the type of that - so you either need c++0x auto or a wrapper function for sort that takes ranges)
I think what you really need (but correct me if I'm wrong) is a way to access elements of a container in some order.
Rather than rearranging my original collection, I would borrow a concept from Database design: keep an index, ordered by a certain criterion. This index is an extra indirection that offers great flexibility.
This way it is possible to generate multiple indices according to different members of a class.
using namespace std;
template< typename Iterator, typename Comparator >
struct Index {
vector<Iterator> v;
Index( Iterator from, Iterator end, Comparator& c ){
v.reserve( std::distance(from,end) );
for( ; from != end; ++from ){
v.push_back(from); // no deref!
}
sort( v.begin(), v.end(), c );
}
};
template< typename Iterator, typename Comparator >
Index<Iterator,Comparator> index ( Iterator from, Iterator end, Comparator& c ){
return Index<Iterator,Comparator>(from,end,c);
}
struct mytype {
string name;
double number;
};
template< typename Iter >
struct NameLess : public binary_function<Iter, Iter, bool> {
bool operator()( const Iter& t1, const Iter& t2 ) const { return t1->name < t2->name; }
};
template< typename Iter >
struct NumLess : public binary_function<Iter, Iter, bool> {
bool operator()( const Iter& t1, const Iter& t2 ) const { return t1->number < t2->number; }
};
void indices() {
mytype v[] = { { "me" , 0.0 }
, { "you" , 1.0 }
, { "them" , -1.0 }
};
mytype* vend = v + _countof(v);
Index<mytype*, NameLess<mytype*> > byname( v, vend, NameLess<mytype*>() );
Index<mytype*, NumLess <mytype*> > bynum ( v, vend, NumLess <mytype*>() );
assert( byname.v[0] == v+0 );
assert( byname.v[1] == v+2 );
assert( byname.v[2] == v+1 );
assert( bynum.v[0] == v+2 );
assert( bynum.v[1] == v+0 );
assert( bynum.v[2] == v+1 );
}
A slightly more compact variant of xtofl's answer for if you are just looking to iterate through all your vectors based on the of a single keys vector. Create a permutation vector and use this to index into your other vectors.
#include <boost/iterator/counting_iterator.hpp>
#include <vector>
#include <algorithm>
std::vector<double> keys = ...
std::vector<double> values = ...
std::vector<size_t> indices(boost::counting_iterator<size_t>(0u), boost::counting_iterator<size_t>(keys.size()));
std::sort(begin(indices), end(indices), [&](size_t lhs, size_t rhs) {
return keys[lhs] < keys[rhs];
});
// Now to iterate through the values array.
for (size_t i: indices)
{
std::cout << values[i] << std::endl;
}
ltjax's answer is a great approach - which is actually implemented in boost's zip_iterator http://www.boost.org/doc/libs/1_43_0/libs/iterator/doc/zip_iterator.html
It packages together into a tuple whatever iterators you provide it.
You can then create your own comparison function for a sort based on any combination of iterator values in your tuple. For this question, it would just be the first iterator in your tuple.
A nice feature of this approach is that it allows you to keep the memory of each individual vector contiguous (if you're using vectors and that's what you want). You also don't need to store a separate index vector of ints.
This would have been an addendum to Konrad's answer as it an approach for a in-place variant of applying the sort order to a vector. Anyhow since the edit won't go through I will put it here
Here is a in-place variant with a slightly higher time complexity that is due to a primitive operation of checking a boolean. The additional space complexity is of a vector which can be a space efficient compiler dependent implementation. The complexity of a vector can be eliminated if the given order itself can be modified.
Here is a in-place variant with a slightly higher time complexity that is due to a primitive operation of checking a boolean. The additional space complexity is of a vector which can be a space efficient compiler dependent implementation. The complexity of a vector can be eliminated if the given order itself can be modified. This is a example of what the algorithm is doing.
If the order is 3 0 4 1 2, the movement of the elements as indicated by the position indices would be 3--->0; 0--->1; 1--->3; 2--->4; 4--->2.
template<typename T>
struct applyOrderinPlace
{
void operator()(const vector<size_t>& order, vector<T>& vectoOrder)
{
vector<bool> indicator(order.size(),0);
size_t start = 0, cur = 0, next = order[cur];
size_t indx = 0;
T tmp;
while(indx < order.size())
{
//find unprocessed index
if(indicator[indx])
{
++indx;
continue;
}
start = indx;
cur = start;
next = order[cur];
tmp = vectoOrder[start];
while(next != start)
{
vectoOrder[cur] = vectoOrder[next];
indicator[cur] = true;
cur = next;
next = order[next];
}
vectoOrder[cur] = tmp;
indicator[cur] = true;
}
}
};
Here is a relatively simple implementation using index mapping between the ordered and unordered names that will be used to match the ages to the ordered names:
void ordered_pairs()
{
std::vector<std::string> names;
std::vector<int> ages;
// read input and populate the vectors
populate(names, ages);
// print input
print(names, ages);
// sort pairs
std::vector<std::string> sortedNames(names);
std::sort(sortedNames.begin(), sortedNames.end());
std::vector<int> indexMap;
for(unsigned int i = 0; i < sortedNames.size(); ++i)
{
for (unsigned int j = 0; j < names.size(); ++j)
{
if (sortedNames[i] == names[j])
{
indexMap.push_back(j);
break;
}
}
}
// use the index mapping to match the ages to the names
std::vector<int> sortedAges;
for(size_t i = 0; i < indexMap.size(); ++i)
{
sortedAges.push_back(ages[indexMap[i]]);
}
std::cout << "Ordered pairs:\n";
print(sortedNames, sortedAges);
}
For the sake of completeness, here are the functions populate() and print():
void populate(std::vector<std::string>& n, std::vector<int>& a)
{
std::string prompt("Type name and age, separated by white space; 'q' to exit.\n>>");
std::string sentinel = "q";
while (true)
{
// read input
std::cout << prompt;
std::string input;
getline(std::cin, input);
// exit input loop
if (input == sentinel)
{
break;
}
std::stringstream ss(input);
// extract input
std::string name;
int age;
if (ss >> name >> age)
{
n.push_back(name);
a.push_back(age);
}
else
{
std::cout <<"Wrong input format!\n";
}
}
}
and:
void print(const std::vector<std::string>& n, const std::vector<int>& a)
{
if (n.size() != a.size())
{
std::cerr <<"Different number of names and ages!\n";
return;
}
for (unsigned int i = 0; i < n.size(); ++i)
{
std::cout <<'(' << n[i] << ", " << a[i] << ')' << "\n";
}
}
And finally, main() becomes:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>
void ordered_pairs();
void populate(std::vector<std::string>&, std::vector<int>&);
void print(const std::vector<std::string>&, const std::vector<int>&);
//=======================================================================
int main()
{
std::cout << "\t\tSimple name - age sorting.\n";
ordered_pairs();
}
//=======================================================================
// Function Definitions...
**// C++ program to demonstrate sorting in vector
// of pair according to 2nd element of pair
#include <iostream>
#include<string>
#include<vector>
#include <algorithm>
using namespace std;
// Driver function to sort the vector elements
// by second element of pairs
bool sortbysec(const pair<char,char> &a,
const pair<int,int> &b)
{
return (a.second < b.second);
}
int main()
{
// declaring vector of pairs
vector< pair <char, int> > vect;
// Initialising 1st and 2nd element of pairs
// with array values
//int arr[] = {10, 20, 5, 40 };
//int arr1[] = {30, 60, 20, 50};
char arr[] = { ' a', 'b', 'c' };
int arr1[] = { 4, 7, 1 };
int n = sizeof(arr)/sizeof(arr[0]);
// Entering values in vector of pairs
for (int i=0; i<n; i++)
vect.push_back( make_pair(arr[i],arr1[i]) );
// Printing the original vector(before sort())
cout << "The vector before sort operation is:\n" ;
for (int i=0; i<n; i++)
{
// "first" and "second" are used to access
// 1st and 2nd element of pair respectively
cout << vect[i].first << " "
<< vect[i].second << endl;
}
// Using sort() function to sort by 2nd element
// of pair
sort(vect.begin(), vect.end(), sortbysec);
// Printing the sorted vector(after using sort())
cout << "The vector after sort operation is:\n" ;
for (int i=0; i<n; i++)
{
// "first" and "second" are used to access
// 1st and 2nd element of pair respectively
cout << vect[i].first << " "
<< vect[i].second << endl;
}
getchar();
return 0;`enter code here`
}**
with C++11 lambdas and the STL algorithms based on answers from Konrad Rudolph and Gabriele D'Antona:
template< typename T, typename U >
std::vector<T> sortVecAByVecB( std::vector<T> & a, std::vector<U> & b ){
// zip the two vectors (A,B)
std::vector<std::pair<T,U>> zipped(a.size());
for( size_t i = 0; i < a.size(); i++ ) zipped[i] = std::make_pair( a[i], b[i] );
// sort according to B
std::sort(zipped.begin(), zipped.end(), []( auto & lop, auto & rop ) { return lop.second < rop.second; });
// extract sorted A
std::vector<T> sorted;
std::transform(zipped.begin(), zipped.end(), std::back_inserter(sorted), []( auto & pair ){ return pair.first; });
return sorted;
}
So many asked this question and nobody came up with a satisfactory answer. Here is a std::sort helper that enables to sort two vectors simultaneously, taking into account the values of only one vector. This solution is based on a custom RadomIt (random iterator), and operates directly on the original vector data, without temporary copies, structure rearrangement or additional indices:
C++, Sort One Vector Based On Another One

Comparing arrays of objects with arrays of fields of objects

Is there a good way to compare arr[i].A to A[i] and arr[i].B to B?
int A[10], B[10];
class Foo {
int A, B;
};
Foo arr[10];
I could do the following:
for (i=0;i<10;i++) {
if (A[i] == arr[i].A) {}
if (B[i] == arr[i].B) {}
}
But, this is painful especially if there are a lot of fields, and the if() conditional does the same thing over and over, there will be a lot of code duplication. What I really want to do is parametrize this somehow and call a function like (test(A,arr)). I guess I can solve this by using #define macros, but that seems ugly.
Any suggestions?
Also I want to avoid creating a new array of Foo objects because I don't want to create new objects that may have many fields I don't care about, also I may want to compare different subsets of fields.
IF the ranges are of equal size you can use std::equal with a predicate (or a lambda):
bool CompA( int lhs, Foo rhs ){
return lhs == rhs.A;
};
...
// to check for equality
bool result = std::equal( A, A + 10, arr, CompA );
...
// to see where the mismatch is
std::pair< int*, Foo* > result = std::mismatch( A, A + 10, arr, CompA );
size_t index = result.first - A;
if( index < 10 ){
std::cout << "Mismatch at index " << index << " A = " << *result.first << " Foo.A = " << (*result.second).A << std::endl;
}
There are standard-library algorithms for doing operations on containers (including arrays, kinda) but using them typically produces code that's harder to read and maintain, and no shorter or more efficient, than straightforward loops.
However, it sounds as if you might want to know about pointers-to-members.
bool all_equal(int Foo::* member, const Foo * obj_array, const int * elem_array, size_t n) {
for (int i=0; i<n; ++i) {
if (obj_array[i].*member != elem_array[i]) return false;
}
return true;
}
...
if (all_equal(&Foo::A, arr, A, 10) && all_equal(&Foo::*B, arr, B, 10)) ...
although actually you should probably generalize it:
template<typename T, typename E>
bool all_equal(E T::* member, const T* obj_array, const E* elem_array, size_t n) {
for (int i=0; i<n; ++i) {
if (obj_array[i].*member != elem_array[i]) return false;
}
return true;
}
(Danger: all code above is untested and may consist entirely of bugs.)