Custom tuple comparator for std::sort() - c++

I have the following situation: I must pack several pointers and an identifier into a tuple like this:
typedef tuple<unsigned*, unsigned*, unsigned*, unsigned> tuple_with_pointers_t;
Here, I have three pointers and one id. In other situations, I may have more or fewer pointers, but the last will be the id. Note that I used unsigned* as an example only. It could be more complex objects.
Now, I want to compare the values of two such tuples. I.e., I need to dereference all tuple elements but the last. We can archive this using the following (in C++17):
template <size_t I = 0, typename T, typename... Ts>
constexpr bool lesser(std::tuple<T, Ts...> a, std::tuple<T, Ts...> b)
{
if constexpr (I < sizeof...(Ts))
return (*std::get<I>(a) < *std::get<I>(b)) ||
((*std::get<I>(a) == *std::get<I>(b)) && lesser<I + 1>(a, b));
else
return std::get<I>(a) < std::get<I>(b);
}
Such construct works very fine when we compare two tuples directly. Now, I would like to use lesser() as a functor on the std::sort(). But, both g++ and clang++ complain that they cannot "couldn't infer template argument '_Compare'". In other words, we need to pass the correct template arguments to lesser.
I have tried some things here, but with no success: we have three template parameters, and I am not sure how I can use the _Elements from the tuple here. What will be the best strategy?
Here is some toy code:
#include <algorithm>
#include <iostream>
#include <tuple>
#include <vector>
using namespace std;
// My weird tuple with pointers and one unsigned index.
typedef tuple<unsigned*, unsigned*, unsigned*, unsigned> tuple_with_pointers_t;
// This works fine for two tuples directly. Note that we cannot dereference
// the last tuple element, so we compare it directly.
template <size_t I = 0, typename T, typename... Ts>
constexpr bool lesser(std::tuple<T, Ts...> a, std::tuple<T, Ts...> b)
{
if constexpr (I < sizeof...(Ts))
return (*std::get<I>(a) < *std::get<I>(b)) ||
((*std::get<I>(a) == *std::get<I>(b)) && lesser<I + 1>(a, b));
else
return std::get<I>(a) < std::get<I>(b);
}
int main() {
// Three sets of values.
vector<unsigned> values1 {1, 2, 3};
vector<unsigned> values2 {10, 20, 30};
vector<unsigned> values3 {11, 22, 33};
// Here, we pack it all together with the index.
vector<tuple_with_pointers_t> all;
for(unsigned i = 0; i < values1.size(); ++i)
all.emplace_back(&values1[i], &values2[i], &values3[i], i);
// So, it works if we want to compare two elements of our vector.
cout << "\n- t0 < t1: " << std::boolalpha << lesser(all[0], all[1]);
cout << "\n- t2 < t1: " << std::boolalpha << lesser(all[2], all[1]);
// Now, I want to sort the tuples by their values. The compiler doesn't
// like it: it cannot deduce the template parameters.
sort(all.begin(), all.end(), lesser);
return 0;
}
I appreciate any help, either using C++17 or C++20. But I'm looking for the most compact and elegant way to do it. It could be using a lambda function directly on the sort() call, too, if possible.
Thanks!
Update:
OK, I found a little hack that works:
sort(all.begin(), all.end(),
[](const auto &a, const auto &b) {
return lesser(a, b);
}
);
Basically, we wrap it into a lambda, and therefore the compiler can deduce the types. But, can we do better?
Thanks

As suggested in the comments, you can add your comparator into a function object and pass an instance of the object to sort:
#include <algorithm>
#include <iostream>
#include <tuple>
#include <vector>
using namespace std;
// My weird tuple with pointers and one unsigned index.
typedef tuple<unsigned*, unsigned*, unsigned*, unsigned> tuple_with_pointers_t;
namespace details {
template <size_t I = 0, typename T, typename... Ts>
constexpr bool lesser(std::tuple<T, Ts...> const& a, std::tuple<T, Ts...> const& b)
{
if constexpr (I < sizeof...(Ts))
return (*std::get<I>(a) < *std::get<I>(b)) ||
((*std::get<I>(a) == *std::get<I>(b)) && lesser<I + 1>(a, b));
else
return std::get<I>(a) < std::get<I>(b);
}
}
struct Less
{
template <typename... Ts>
constexpr bool operator()(std::tuple<Ts...> const& a, std::tuple<Ts...> const& b)
{
return details::lesser<0, Ts...>(a, b);
}
};
int main() {
// Three sets of values.
vector<unsigned> values1 {1, 2, 3};
vector<unsigned> values2 {10, 20, 30};
vector<unsigned> values3 {11, 22, 33};
// Here, we pack it all together with the index.
vector<tuple_with_pointers_t> all;
for(unsigned i = 0; i < values1.size(); ++i)
all.emplace_back(&values1[i], &values2[i], &values3[i], i);
// So, it works if we want to compare two elements of our vector.
cout << "\n- t0 < t1: " << std::boolalpha << Less()(all[0], all[1]);
cout << "\n- t2 < t1: " << std::boolalpha << Less()(all[2], all[1]);
// Now, I want to sort the tuples by their values. The compiler doesn't
// like it: it cannot deduce the template parameters.
sort(all.begin(), all.end(), Less());
return 0;
}
As an alternative, you could wrap your unsigned* in a custom pointer type and provide a comparator for it. Then you can use the default comperator for tuples, which compares the elements lexicographically.
I personally would prefer this approach, because the code is much more readable. I don't know if this would break your existing code or would entail a huge refactor.
#include <algorithm>
#include <iostream>
#include <tuple>
#include <vector>
using namespace std;
class Ptr
{
public:
Ptr(unsigned& v) : m_ptr(&v) {}
unsigned operator*() const {
return *m_ptr;
}
private:
unsigned* m_ptr;
};
bool operator<(Ptr const& l, Ptr const& r)
{
return *l < *r;
}
// My weird tuple with pointers and one unsigned index.
typedef tuple<Ptr, Ptr, Ptr, unsigned> tuple_with_pointers_t;
int main() {
// Three sets of values.
vector<unsigned> values1 {1, 2, 3};
vector<unsigned> values2 {10, 20, 30};
vector<unsigned> values3 {11, 22, 33};
// Here, we pack it all together with the index.
vector<tuple_with_pointers_t> all;
for(unsigned i = 0; i < values1.size(); ++i)
all.emplace_back(values1[i], values2[i], values3[i], i);
// So, it works if we want to compare two elements of our vector.
cout << "\n- t0 < t1: " << std::boolalpha << (all[0] < all[1]);
cout << "\n- t2 < t1: " << std::boolalpha << (all[2] < all[1]);
sort(all.begin(), all.end());
return 0;
}

I think we can use this. Of course, I don't know your tuple can be more complex.
template<typename T, size_t I = 0>
using type_tuple = typename std::tuple_element<I,T>::type;
template<size_t I = 0, template<typename> class F = std::less_equal>
struct TupleCompare
{
template<typename T>
bool operator()(T const &t1, T const &t2){
using _type = typename std::conditional<std::is_pointer<type_tuple<T>>::value,
typename std::remove_pointer<type_tuple<T,I>>::type, type_tuple<T>>::type;
if constexpr (I == std::tuple_size_v<T> - 1) {
return F<_type>()(std::get<I>(t1), std::get<I>(t2));
} else {
return F<_type>()(*std::get<I>(t1), *std::get<I>(t2)) && TupleCompare<I+1, F>()(t1, t2);
}
}
};

By doing a non-"recursive" function, you might do a "one-liner":
sort(all.begin(), all.end(),
[]<typename T>(const T& lhs, const T& rhs) {
return [&]<std::size_t... Is>(std::index_sequence<Is...>){
return std::tie(std::get<Is>(lhs)...)
< std::tie(std::get<Is>(rhs)...);
}(std::make_index_sequence<std::tuple_size_v<T> - 1>{});
});
template lambda are C++20.
Without that, at least an helper function is required, so it becomes, as the other solutions, wrapping a function in a functor.

Related

Given a tuple with arbitrary number of vectors holding different types how do I extract the vector with minimum size?

In my application I generate a tuple with many vectors holding values. I would like to have a generic way of iterating over the tuple to extract the single vector with least values.
For example:
auto t = std::make_tuple(std::vector<int>({1,2}), std::vector<double>({1.0, 2.0, 3.0}));
How do I extract the vector which holds the least values?
Given a tuple with vectors holding different types how do I extract the vector with minimum size?
You can't You can't directly.
Because they are different types, the decision is based on values (not on types), so you can't decide the type extracted compile time (std::tuple can't be constexpr), and C++ is a strong typed language.
The best simplest thing you can do is extract the index of the vector with minimum size. Because in this case the value extracted is an integer (std::size_t, by example) and you can iterate the over the vectors in the tuple to select the one with less elements.
Different is if you have to extract the std::array with minimum size
auto t = std::make_tuple(std::array<int, 2u>({1,2}),
std::array<double, 3u>({1.0, 2.0, 3.0}));
because the size (2u for the first, 3u for the second) is know compile time so you can select the second array compile time.
If you can use C++17, you can use std::variant, so a type that can contain all types of your tuple.
As pointed by Caleth (thanks) if you can use only C++11/C++14 with boost libraries, you can use boost::variant. But I don't know it so I can't show you a specific example (but you can see the Caleth's answer)
The following is an example with a two-types tuple
template <typename T1, typename T2>
std::variant<T1, T2> getLess (std::tuple<T1, T2> const & tp)
{
std::variant<T1, T2> v;
if ( std::get<0>(tp).size() < std::get<1>(tp).size() )
v = std::get<0>(tp);
else
v = std::get<1>(tp);
return v;
}
int main ()
{
std::vector<int> vi {1, 2, 3};
std::vector<double> vd {1.0, 2.0};
auto gl = getLess(std::make_tuple(vi, vd));
}
This works with a two types tuple. But with a N-types tuple (with N high) become complicated because you can't write something as
auto min_length = std::get<0>(tp).size();
auto min_index = 0u;
for ( auto ui = 1u ; ui < N ; ++ui )
if ( std::get<ui>(tp).size() < min_length )
{
min_length = std::get<ui>(tp).size();
min_index = ui;
}
because you can't pass to std::get<>() a run-time value as ui.
Same problem assigning the variant. You can't simply write
v = std::get<min_index>(tp);
because min_index is a run-time value.
You have to pass through a switch()
switch ( min_length )
{
case 0: v = std::get<0>(tp); break;
case 1: v = std::get<1>(tp); break;
case 2: v = std::get<2>(tp); break;
case 3: v = std::get<3>(tp); break;
case 4: v = std::get<4>(tp); break;
// ...
case N-1: v = std::get<N-1>(tp); break;
};
or something similar.
As you can see it's complicated and more complicated become if you want that the getLess() function is a variadic one.
For the variadic case, the best I can imagine (but is a C++17 solution; see Caleth's answer for a C++11 solution) is to use an helper function and template folding as follows.
#include <tuple>
#include <vector>
#include <variant>
#include <iostream>
template <typename ... Ts, std::size_t ... Is>
auto getLessHelper (std::tuple<Ts...> const & tp,
std::index_sequence<0, Is...> const &)
{
std::variant<Ts...> var_ret { std::get<0>(tp) };
std::size_t min_size { std::get<0>(tp).size() };
((std::get<Is>(tp).size() < min_size ? (var_ret = std::get<Is>(tp),
min_size = std::get<Is>(tp).size())
: 0u), ...);
return var_ret;
}
template <typename ... Ts>
auto getLess (std::tuple<Ts...> const & tp)
{ return getLessHelper(tp, std::index_sequence_for<Ts...>{}); }
int main ()
{
std::vector<int> vi {1, 2, 3};
std::vector<double> vd {1.0, 2.0};
std::vector<float> vf {1.0f};
auto gl = getLess(std::make_tuple(vi, vd, vf));
std::cout << std::visit([](auto const & v){ return v.size(); }, gl)
<< std::endl; // print 1, the size() of vf
}
Let's assume we either have no duplicates in our pack of types, or a way of removing them, and also a C++11 backport of std::index_sequence
#include <map>
#include <tuple>
#include <functional>
#include <iostream>
#include <boost/variant>
#include <future/index_sequence>
namespace detail {
template<typename Variant, typename Tuple, std::size_t... Is>
std::map<std::size_t, std::function<Variant(const Tuple &)>> from_tuple_map(index_sequence<Is...>)
{
return { { Is, [](const Tuple & tup){ return std::get<Is>(tup); } }... };
}
struct GetSize
{
template<typename T>
std::size_t operator()(const std::vector<T> & vec){ return vec.size(); }
}; // becomes C++14 generic lambda
}
template<typename... Ts>
boost::variant<Ts...> from_tuple(const std::tuple<Ts...> & tup)
{
auto map = detail::from_tuple_map<boost::variant<Ts...>, std::tuple<Ts...>>(make_index_sequence<sizeof...(Ts)>());
auto get_size = GetSize{};
std::size_t best = 0;
std::size_t len = visit(get_size, map[best](tup));
for (std::size_t trial = 1; trial < sizeof...(Ts); ++trial)
{
std::size_t trial_len = visit(get_size, map[trial](tup));
if (trial_len > len)
{
best = trial;
len = trial_len;
}
}
return map[best](tup);
}
int main()
{
auto x = from_tuple(std::make_tuple(std::vector<int>({1,2}), std::vector<double>({1.0, 2.0, 3.0})));
visit([](const auto & a){ std::cout << a[1]; }, x);
}
See it live (using C++17 compiler)

C++ STL: std::find with std::map

Python allows you to write if e in arr: ... and if key in dict: ... which is handy.
Can we do something similar with the latter using std::find() and std::map ? That will allow me to uniformly handle std::array and std::map with a single generic function, without explicitly switching to std::map::find().
But if overloading operator==() is the only way, I'd rather give up this idea...
Update: note I already have a sort of solution
By "overloading operator==()" I meant something like this:
template<typename K>
struct KF {
K&& k;
template <typename V>
friend bool operator==(const typename std::pair<const K, V>& pair, const KF<K>& o) {
return pair.first == o.k;
}
};
template <typename K>
KF<K> keyFinder(K&& k) { return KF<K>{ std::forward<K>(k) }; }
int main() {
std::set<int> s{ 1, 2, };
cout << (std::find(s.begin(), s.end(), 1) == s.end()) << endl; // => 0
cout << (std::find(s.begin(), s.end(), 3) == s.end()) << endl; // => 1
std::map<int, int> m{ {1,10}, {2,20}, };
cout << (std::find(m.begin(), m.end(), keyFinder(1)) == m.end()) << endl; // => 0
cout << (std::find(m.begin(), m.end(), keyFinder(3)) == m.end()) << endl; // => 1
}
http://ideone.com/7ULUe9
Things get more complicated when we deal with non-scalar K in an universal way (perfect forwarding etc. ?)
...why not write your own utility function?
template <typename TContainer, typename TValue>
bool contains(const TContainer& c, const TValue& x);
You can use overloading to match the containers:
template <typename TValue, std::size_t N>
bool contains(const std::array<TValue, N>& c, const TValue& x)
{
return std::find(std::begin(c), std::end(c), x) != std::end(c);
}
template <typename TValue, typename... Ts>
bool contains(const std::map<Ts...>& c, const TValue& x)
{
return c.find(x) != std::end(c);
}
Usage:
std::array<int, 2> a{1,2};
std::map<int, int> b{{1,2},{3,4}};
assert(contains(a, 1));
assert(!contains(a, 42));
assert(contains(b, 1));
assert(!contains(b, 42));
live example on wandbox
If you want to support additional containers in the future, it's a good idea to use SFINAE to check whether or not a particular expression is valid. This approach works well because it doesn't care about the type of the container, it only cares about what operations can be performed on it.
The detection idiom would likely make it very easy to check member availability through SFINAE (and its implementation is C++11 compatible).
I also wrote an article about checking expression validity in-situ with C++17, which could be an interesting read. Despite its title, it covers C++11, C++14 and C++17 techniques to check expression validity:
"checking expression validity in-place with C++17"
To answer your explicit question - no, std::find won't be able to work uniformly for std::map/std::unordered_map and std::array/std::vector as the former is a collection of key/value pairs and the latter is collection of values...
You may want to use std::find_if instead as it gives you a little bit more flexibility on defining equality condition e.g. like this (c++1z approach):
#include <array>
#include <map>
#include <string>
#include <algorithm>
#include <type_traits>
template <class T>
struct is_pair: std::false_type { };
template <class K, class V>
struct is_pair<std::pair<K,V>>: std::true_type { };
int main() {
std::map<std::string, int> m {{"abc", 1}, {"cde", 2}, {"efg", 3}};
std::array<int, 5> a{1, 2, 3, 4, 5};
auto lambda = [](auto it) {
if constexpr (is_pair<decltype(it)>::value) {
return it.second == 3;
} else {
return it == 3;
}
};
assert(std::find_if(a.begin(), a.end(), lambda) != a.end());
assert(std::find_if(m.begin(), m.end(), lambda) != m.end());
}
[live demo]
Have in mind that this approach won't work as expected if you decide to search through collection like std::vector<std::pair<int, int>>.

Clean ways to write multiple 'for' loops

For an array with multiple dimensions, we usually need to write a for loop for each of its dimensions. For example:
vector< vector< vector<int> > > A;
for (int k=0; k<A.size(); k++)
{
for (int i=0; i<A[k].size(); i++)
{
for (int j=0; j<A[k][i].size(); j++)
{
do_something_on_A(A[k][i][j]);
}
}
}
double B[10][8][5];
for (int k=0; k<10; k++)
{
for (int i=0; i<8; i++)
{
for (int j=0; j<5; j++)
{
do_something_on_B(B[k][i][j]);
}
}
}
You see this kind of for-for-for loops in our code frequently. How do I use macros to define the for-for-for loops so that I don't need to re-write this kind of code every time? Is there a better way to do this?
The first thing is that you don't use such a data structure. If
you need a three dimensional matrix, you define one:
class Matrix3D
{
int x;
int y;
int z;
std::vector<int> myData;
public:
// ...
int& operator()( int i, int j, int k )
{
return myData[ ((i * y) + j) * z + k ];
}
};
Or if you want to index using [][][], you need an operator[]
which returns a proxy.
Once you've done this, if you find that you constantly have to
iterate as you've presented, you expose an iterator which will
support it:
class Matrix3D
{
// as above...
typedef std::vector<int>::iterator iterator;
iterator begin() { return myData.begin(); }
iterator end() { return myData.end(); }
};
Then you just write:
for ( Matrix3D::iterator iter = m.begin(); iter != m.end(); ++ iter ) {
// ...
}
(or just:
for ( auto& elem: m ) {
}
if you have C++11.)
And if you need the three indexes during such iterations, it's
possible to create an iterator which exposes them:
class Matrix3D
{
// ...
class iterator : private std::vector<int>::iterator
{
Matrix3D const* owner;
public:
iterator( Matrix3D const* owner,
std::vector<int>::iterator iter )
: std::vector<int>::iterator( iter )
, owner( owner )
{
}
using std::vector<int>::iterator::operator++;
// and so on for all of the iterator operations...
int i() const
{
((*this) - owner->myData.begin()) / (owner->y * owner->z);
}
// ...
};
};
Using a macro to hide the for loops can be a lot confusing, just to save few characters. I'd use range-for loops instead:
for (auto& k : A)
for (auto& i : k)
for (auto& j : i)
do_something_on_A(j);
Of course you can replace auto& with const auto& if you are, in fact, not modifying the data.
Something like this can help:
template <typename Container, typename Function>
void for_each3d(const Container &container, Function function)
{
for (const auto &i: container)
for (const auto &j: i)
for (const auto &k: j)
function(k);
}
int main()
{
vector< vector< vector<int> > > A;
for_each3d(A, [](int i){ std::cout << i << std::endl; });
double B[10][8][5] = { /* ... */ };
for_each3d(B, [](double i){ std::cout << i << std::endl; });
}
In order to make it N-ary we need some template magic. First of all we should create SFINAE structure to distinguish whether this value or container. The default implementation for values, and specialisations for arrays and each of the container types. How #Zeta notes, we can determine the standard containers by the nested iterator type (ideally we should check whether the type can be used with range-base for or not).
template <typename T>
struct has_iterator
{
template <typename C>
constexpr static std::true_type test(typename C::iterator *);
template <typename>
constexpr static std::false_type test(...);
constexpr static bool value = std::is_same<
std::true_type, decltype(test<typename std::remove_reference<T>::type>(0))
>::value;
};
template <typename T>
struct is_container : has_iterator<T> {};
template <typename T>
struct is_container<T[]> : std::true_type {};
template <typename T, std::size_t N>
struct is_container<T[N]> : std::true_type {};
template <class... Args>
struct is_container<std::vector<Args...>> : std::true_type {};
Implementation of for_each is straightforward. The default function will call function:
template <typename Value, typename Function>
typename std::enable_if<!is_container<Value>::value, void>::type
rfor_each(const Value &value, Function function)
{
function(value);
}
And the specialisation will call itself recursively:
template <typename Container, typename Function>
typename std::enable_if<is_container<Container>::value, void>::type
rfor_each(const Container &container, Function function)
{
for (const auto &i: container)
rfor_each(i, function);
}
And voila:
int main()
{
using namespace std;
vector< vector< vector<int> > > A;
A.resize(3, vector<vector<int> >(3, vector<int>(3, 5)));
rfor_each(A, [](int i){ std::cout << i << ", "; });
// 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
std::cout << std::endl;
double B[3][3] = { { 1. } };
rfor_each(B, [](double i){ std::cout << i << ", "; });
// 1, 0, 0, 0, 0, 0, 0, 0, 0,
}
Also this will not work for pointers (arrays allocated in heap).
Most of the answers simply demonstrate how C++ can be twisted into incomprehensible syntactic extensions, IMHO.
By defining whatever templates or macros, you just force other programmers to understand bits of obfuscated code designed to hide other bits of obfuscated code.
You will force every guy who reads your code to have template expertise, just to avoid doing your job of defining objects with clear semantics.
If you decided to use raw data like 3 dimensional arrays, just live with it, or else define a class that gives some understandable meaning to your data.
for (auto& k : A)
for (auto& i : k)
for (auto& current_A : i)
do_something_on_A(current_A);
is just consistent with the cryptic definition of a vector of vector of vector of int with no explicit semantics.
#include "stdio.h"
#define FOR(i, from, to) for(int i = from; i < to; ++i)
#define TRIPLE_FOR(i, j, k, i_from, i_to, j_from, j_to, k_from, k_to) FOR(i, i_from, i_to) FOR(j, j_from, j_to) FOR(k, k_from, k_to)
int main()
{
TRIPLE_FOR(i, j, k, 0, 3, 0, 4, 0, 2)
{
printf("i: %d, j: %d, k: %d\n", i, j, k);
}
return 0;
}
UPDATE: I know, that you asked for it, but you'd better not use that :)
One idea is to write an iterable pseudo-container class that "contains" the set of all multi-index tuples you'll index over. No implementation here because it'll take too long but the idea is that you should be able to write...
multi_index mi (10, 8, 5);
// The pseudo-container whose iterators give {0,0,0}, {0,0,1}, ...
for (auto i : mi)
{
// In here, use i[0], i[1] and i[2] to access the three index values.
}
I see many answers here that work recursively, detecting if the input is a container or not. Instead, why not detect if the current layer is the same type as the function takes? It's far simpler, and allows for more powerful functions:
//This is roughly what we want for values
template<class input_type, class func_type>
void rfor_each(input_type&& input, func_type&& func)
{ func(input);}
//This is roughly what we want for containers
template<class input_type, class func_type>
void rfor_each(input_type&& input, func_type&& func)
{ for(auto&& i : input) rfor_each(i, func);}
However, this (obviously) gives us ambiguity errors. So we use SFINAE to detect if the current input fits in the function or not
//Compiler knows to only use this if it can pass input to func
template<class input_type, class func_type>
auto rfor_each(input_type&& input, func_type&& func) ->decltype(func(input))
{ return func(input);}
//Otherwise, it always uses this one
template<class input_type, class func_type>
void rfor_each(input_type&& input, func_type&& func)
{ for(auto&& i : input) rfor_each(i, func);}
This now handles the containers correctly, but the compiler still considers this ambiguous for input_types that can be passed to the function. So we use a standard C++03 trick to make it prefer the first function over the second, of also passing a zero, and making the one we prefer accept and int, and the other takes ...
template<class input_type, class func_type>
auto rfor_each(input_type&& input, func_type&& func, int) ->decltype(func(input))
{ return func(input);}
//passing the zero causes it to look for a function that takes an int
//and only uses ... if it absolutely has to
template<class input_type, class func_type>
void rfor_each(input_type&& input, func_type&& func, ...)
{ for(auto&& i : input) rfor_each(i, func, 0);}
That's it. Six, relatively simple lines of code, and you can iterate over values, rows, or any other sub-unit, unlike all of the other answers.
#include <iostream>
int main()
{
std::cout << std::endl;
double B[3][3] = { { 1.2 } };
rfor_each(B[1], [](double&v){v = 5;}); //iterate over doubles
auto write = [](double (&i)[3]) //iterate over rows
{
std::cout << "{";
for(double d : i)
std::cout << d << ", ";
std::cout << "}\n";
};
rfor_each(B, write );
};
Proof of compilation and execution here and here
If you wanted a more convenient syntax in C++11, you could add a macro. (Following is untested)
template<class container>
struct container_unroller {
container& c;
container_unroller(container& c_) :c(c_) {}
template<class lambda>
void operator <=(lambda&& l) {rfor_each(c, l);}
};
#define FOR_NESTED(type, index, container) container_unroller(container) <= [](type& index)
//note that this can't handle functions, function pointers, raw arrays, or other complex bits
int main() {
double B[3][3] = { { 1.2 } };
FOR_NESTED(double, v, B) {
std::cout << v << ", ";
}
}
I caveat this answer with the following statement: this would only work if you were operating on an actual array - it wouldn't work for your example using std::vector.
If you are performing the same operation on every element of a multi-dimensional array, without caring about the position of each item, then you can take advantage of the fact that arrays are placed in contiguous memory locations, and treat the whole thing as one big one-dimensional array. For example, if we wanted to multiply every element by 2.0 in your second example:
double B[3][3][3];
// ... set the values somehow
double* begin = &B[0][0][0]; // get a pointer to the first element
double* const end = &B[3][0][0]; // get a (const) pointer past the last element
for (; end > begin; ++begin) {
(*begin) *= 2.0;
}
Note that using the above approach also allows the use of some "proper" C++ techniques:
double do_something(double d) {
return d * 2.0;
}
...
double B[3][3][3];
// ... set the values somehow
double* begin = &B[0][0][0]; // get a pointer to the first element
double* end = &B[3][0][0]; // get a pointer past the last element
std::transform(begin, end, begin, do_something);
I don't generally advise this approach (preferring something like Jefffrey's answer), as it relies on having defined sizes for your arrays, but in some cases it can be useful.
I was kind of shocked that no one proposed some arithmetic-magic based loop to do the work. Since C. Wang is looking for a solution with no nested loops, I'll propose one:
double B[10][8][5];
int index = 0;
while (index < (10 * 8 * 5))
{
const int x = index % 10,
y = (index / 10) % 10,
z = index / 100;
do_something_on_B(B[x][y][z]);
++index;
}
Well, this approach isn't elegant and flexible, so we could pack all the process into a template function:
template <typename F, typename T, int X, int Y, int Z>
void iterate_all(T (&xyz)[X][Y][Z], F func)
{
const int limit = X * Y * Z;
int index = 0;
while (index < limit)
{
const int x = index % X,
y = (index / X) % Y,
z = index / (X * Y);
func(xyz[x][y][z]);
++index;
}
}
This template function can be expressed in the form of nested loops as well:
template <typename F, typename T, int X, int Y, int Z>
void iterate_all(T (&xyz)[X][Y][Z], F func)
{
for (auto &yz : xyz)
{
for (auto &z : yz)
{
for (auto &v : z)
{
func(v);
}
}
}
}
And can be used providing a 3D array of arbitrary size plus the function name, letting the parameter deduction do the hard work of counting the size of each dimension:
int main()
{
int A[10][8][5] = {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}};
int B[7][99][8] = {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}};
iterate_all(A, do_something_on_A);
iterate_all(B, do_something_on_B);
return 0;
}
Towards more generic
But once again, it lacks of flexibility 'cause it only works for 3D arrays, but using SFINAE we can do the work for arrays of an arbitrary dimension, first we need a template function which iterates arrays of rank 1:
template<typename F, typename A>
typename std::enable_if< std::rank<A>::value == 1 >::type
iterate_all(A &xyz, F func)
{
for (auto &v : xyz)
{
func(v);
}
}
And another one which iterates arrays of any rank, doing the recursion:
template<typename F, typename A>
typename std::enable_if< std::rank<A>::value != 1 >::type
iterate_all(A &xyz, F func)
{
for (auto &v : xyz)
{
iterate_all(v, func);
}
}
This allows us to iterate all the elements in all the dimensions of a arbitrary-dimensions arbitrary-sized array.
Working with std::vector
For the multiple nested vector, the solution ressembles the one of arbitrary-dimensions arbitrary-sized array, but without SFINAE: First we will need a template function that iterates std::vectors and calls the desired function:
template <typename F, typename T, template<typename, typename> class V>
void iterate_all(V<T, std::allocator<T>> &xyz, F func)
{
for (auto &v : xyz)
{
func(v);
}
}
And another template function that iterates any kind of vector of vectors and calls himself:
template <typename F, typename T, template<typename, typename> class V>
void iterate_all(V<V<T, std::allocator<T>>, std::allocator<V<T, std::allocator<T>>>> &xyz, F func)
{
for (auto &v : xyz)
{
iterate_all(v, func);
}
}
Regardless of the nesting level, iterate_all will call the vector-of-vectors version unless the vector-of-values version is a better match thus ending the recursivity.
int main()
{
using V0 = std::vector< std::vector< std::vector<int> > >;
using V1 = std::vector< std::vector< std::vector< std::vector< std::vector<int> > > > >;
V0 A0 = {{{0, 1}, {2, 3}}, {{4, 5}, {6, 7}}};
V1 A1 = {{{{{9, 8}, {7, 6}}, {{5, 4}, {3, 2}}}}};
iterate_all(A0, do_something_on_A);
iterate_all(A1, do_something_on_A);
return 0;
}
I think that the function body is pretty simple and straight-forward... I wonder if the compiler could unroll this loops (I'm almost sure that most compilers could unroll the first example).
See live demo here.
Hope it helps.
Use something along these lines (its pseudo-code, but the idea stays the same). You extract the pattern to loop once, and apply a different function each time.
doOn( structure A, operator o)
{
for (int k=0; k<A.size(); k++)
{
for (int i=0; i<A[k].size(); i++)
{
for (int j=0; j<A[k][i].size(); j++)
{
o.actOn(A[k][i][j]);
}
}
}
}
doOn(a, function12)
doOn(a, function13)
Stick with the nested for loops!
All the methods suggested here have disadvantages in terms of either readability or flexibility.
What happens if you need to use the results of an inner loop for the processing in the outer loop? What happens if you need a value from the outer loop within your inner loop? Most of the "encapsulation" methods fail here.
Trust me I have seen several attempts to "clean up" nested for loops and in the end it turns out that the nested loop is actually the cleanest and most flexible solution.
One technique I've used is templates. E.g.:
template<typename T> void do_something_on_A(std::vector<T> &vec) {
for (auto& i : vec) { // can use a simple for loop in C++03
do_something_on_A(i);
}
}
void do_something_on_A(int &val) {
// this is where your `do_something_on_A` method goes
}
Then you simply call do_something_on_A(A) in your main code. The template function gets created once for each dimension, the first time with T = std::vector<std::vector<int>>, the second time with with T = std::vector<int>.
You could make this more generic using std::function (or function-like objects in C++03) as a second argument if you want:
template<typename T> void do_something_on_vec(std::vector<T> &vec, std::function &func) {
for (auto& i : vec) { // can use a simple for loop in C++03
do_something_on_vec(i, func);
}
}
template<typename T> void do_something_on_vec(T &val, std::function &func) {
func(val);
}
Then call it like:
do_something_on_vec(A, std::function(do_something_on_A));
This works even though the functions have the same signature because the first function is a better match for anything with std::vector in the type.
You could generate indices in one loop like this (A, B, C are dimensions):
int A = 4, B = 3, C = 3;
for(int i=0; i<A*B*C; ++i)
{
int a = i/(B*C);
int b = (i-((B*C)*(i/(B*C))))/C;
int c = i%C;
}
One thing you may want to try if you only have statements in the inner-most loop - and your concern is more about the overly verbose nature of the code - is to use a different whitespace scheme. This will only work if you can state your for loops compactly enough so that they all fit on one line.
For your first example, I would rewrite it as:
vector< vector< vector<int> > > A;
int i,j,k;
for(k=0;k<A.size();k++) for(i=0;i<A[k].size();i++) for(j=0;j<A[k][i].size();j++) {
do_something_on_A(A[k][i][j]);
}
This is kinda pushing it because you are calling functions in the outer loops which is equivalent to putting statements in them. I have removed all unnecessary white-space and it may be passible.
The second example is much better:
double B[10][8][5];
int i,j,k;
for(k=0;k<10;k++) for(i=0;i<8;i++) for(j=0;j<5;j++) {
do_something_on_B(B[k][i][j]);
}
This may be different whitespace convention than you like to use, but it achieves a compact result that nonetheless does not require any knowledge beyond C/C++ (such as macro conventions) and does not require any trickery like macros.
If you really want a macro, you could then take this a step further with something like:
#define FOR3(a,b,c,d,e,f,g,h,i) for(a;b;c) for(d;e;f) for(g;h;i)
which would change the second example to:
double B[10][8][5];
int i,j,k;
FOR3(k=0,k<10,k++,i=0,i<8,i++,j=0,j<5,j++) {
do_something_on_B(B[k][i][j]);
}
and the first example fares better too:
vector< vector< vector<int> > > A;
int i,j,k;
FOR3(k=0,k<A.size(),k++,i=0,i<A[k].size(),i++,j=0,j<A[k][i].size(),j++) {
do_something_on_A(A[k][i][j]);
}
Hopefully you can tell fairly easily which statements go with which for statements. Also, beware the commas, now you can't use them in a single clause of any of the fors.
Here is a C++11 implementation that handles everything iterable. Other solutions restrict themselves to containers with ::iterator typedefs or arrays: but a for_each is about iteration, not being a container.
I also isolate the SFINAE to a single spot in the is_iterable trait. The dispatching (between elements and iterables) is done via tag dispatching, which I find is a clearer solution.
The containers and the functions applied to elements are all perfect forwarded, allowing both const and non-const access to the ranges and functors.
#include <utility>
#include <iterator>
The template function I am implementing. Everything else could go into a details namespace:
template<typename C, typename F>
void for_each_flat( C&& c, F&& f );
Tag dispatching is much cleaner than SFINAE. These two are used for iterable objects and non iterable objects respectively. The last iteration of the first could use perfect forwarding, but I am lazy:
template<typename C, typename F>
void for_each_flat_helper( C&& c, F&& f, std::true_type /*is_iterable*/ ) {
for( auto&& x : std::forward<C>(c) )
for_each_flat(std::forward<decltype(x)>(x), f);
}
template<typename D, typename F>
void for_each_flat_helper( D&& data, F&& f, std::false_type /*is_iterable*/ ) {
std::forward<F>(f)(std::forward<D>(data));
}
This is some boilerplate required in order to write is_iterable. I do argument dependent lookup on begin and end in a detail namespace. This emulates what a for( auto x : y ) loop does reasonably well:
namespace adl_aux {
using std::begin; using std::end;
template<typename C> decltype( begin( std::declval<C>() ) ) adl_begin(C&&);
template<typename C> decltype( end( std::declval<C>() ) ) adl_end(C&&);
}
using adl_aux::adl_begin;
using adl_aux::adl_end;
The TypeSink is useful to test if code is valid. You do TypeSink< decltype( code ) > and if the code is valid, the expression is void. If the code is not valid, SFINAE kicks in and the specialization is blocked:
template<typename> struct type_sink {typedef void type;};
template<typename T> using TypeSink = typename type_sink<T>::type;
template<typename T, typename=void>
struct is_iterable:std::false_type{};
template<typename T>
struct is_iterable<T, TypeSink< decltype( adl_begin( std::declval<T>() ) ) >>:std::true_type{};
I only test for begin. An adl_end test could also be done.
The final implementation of for_each_flat ends up being extremely simple:
template<typename C, typename F>
void for_each_flat( C&& c, F&& f ) {
for_each_flat_helper( std::forward<C>(c), std::forward<F>(f), is_iterable<C>() );
}
Live example
This is way down at the bottom: feel free to poach for the top answers, which are solid. I just wanted a few better techniques to be used!
Firstly, you shouldn't use a vector of vectors of vectors. Each vector is guaranteed to have contiguous memory, but the "global" memory of a vector of vectors isn't (and probably won't be). You should use the standard library type array instead of C-style arrays as well.
using std::array;
array<array<array<double, 5>, 8>, 10> B;
for (int k=0; k<10; k++)
for (int i=0; i<8; i++)
for (int j=0; j<5; j++)
do_something_on_B(B[k][i][j]);
// or, if you really don't like that, at least do this:
for (int k=0; k<10; k++) {
for (int i=0; i<8; i++) {
for (int j=0; j<5; j++) {
do_something_on_B(B[k][i][j]);
}
}
}
Better yet though, you could define a simple 3D matrix class:
#include <stdexcept>
#include <array>
using std::size_t;
template <size_t M, size_t N, size_t P>
class matrix3d {
static_assert(M > 0 && N > 0 && P > 0,
"Dimensions must be greater than 0.");
std::array<std::array<std::array<double, P>, N>, M> contents;
public:
double& at(size_t i, size_t j, size_t k)
{
if (i >= M || j >= N || k >= P)
throw out_of_range("Index out of range.");
return contents[i][j][k];
}
double& operator(size_t i, size_t j, size_t k)
{
return contents[i][j][k];
}
};
int main()
{
matrix3d<10, 8, 5> B;
for (int k=0; k<10; k++)
for (int i=0; i<8; i++)
for (int j=0; j<5; j++)
do_something_on_B(B(i,j,k));
return 0;
}
You could go further and make it fully const-correct, add matrix multiplication (proper and element-wise), multiplication by vectors, etc. You could even generalise it to different types (I'd make it template if you mainly use doubles).
You could also add proxy objects so you can do B[i] or B[i][j]. They could return vectors (in the mathematical sense) and matrices full of double&, potentially?

How can I implement a custom template sort function?

I have a vector of pairs that I want to be stable sorted only by the key (which may occur multiple times). I do not use a multimap for this, because it is not explicitly stable. Therefore, I supply a custom compare function to stable_sort. I'm struggling now with templatizing this function. A brief test implementation follows to show you the use case:
#include <iostream>
#include <algorithm>
#include <vector>
#include "test.h"
using namespace std;
int main() {
typedef pair<int, int> TPair;
vector<TPair> data(10);
data[0] = make_pair(7, 1);
data[1] = make_pair(3, 2);
data[2] = make_pair(8, 0);
data[3] = make_pair(5, 1);
data[4] = make_pair(3, 1);
data[5] = make_pair(2, 0);
data[6] = make_pair(7, 0);
data[7] = make_pair(6, 0);
data[8] = make_pair(5, 0);
data[9] = make_pair(3, 0);
stable_sort(data.begin(), data.end(), comp1);
for (unsigned int i = 0; i < 10; ++i) {
cout << data[i].first << "\t" << data[i].second << endl;
}
return 0;
}
The supplied sorting function is available in test.h:
#include <vector>
#ifndef TEST_H_
#define TEST_H_
using namespace std;
bool comp1(pair<int, int> const & a, pair<int, int> const & b) {
return a.first < b.first;
}
template <typename TElemA, typename TElemB>
bool comp2(pair<TElemA, TElemB> const & a, pair<TElemA, TElemB> const & b) {
return a.first < b.first;
}
template <typename TPair>
bool comp3(TPair const & a, TPair const & b) {
return a.first < b.first;
}
#endif
comp1 works well, nothing to complain. First I tried to templatize the elements of the pairs:
comp2 doesn't work: test.cpp:25:3: error: no matching function for call to 'stable_sort'.
comp3 fails with the same error message as comp2.
What is wrong with this template function?
stable_sort is itself a template, the type of its third parameter is a template parameter. This means that you cannot pass a function template as the argument, because template argument deduction cannot apply here - there's nothing to tell which instantiation you'd be after. So you'd have to specify the template argument explicitly:
stable_sort(data.begin(), data.end(), comp2<int, int>);
However, you'll be better off if you provide a functor for that:
struct comp2
{
template <typename TElemA, typename TElemB>
bool operator() (pair<TElemA, TElemB> const & a, pair<TElemA, TElemB> const & b) const {
return a.first < b.first;
}
};
stable_sort(data.begin(), data.end(), comp2());
That way, the actual template argument deduction is postponed until the time when the desired types are known.
Since C++14, you can also use a lambda expression instead of using a template. This is, because C++14 allows for generic lambdas, whose function parameters can be declared with the auto type specifier:
std::stable_sort(std::begin(data), std::end(data), [](auto const &a, auto const &b){
return a.first < b.first;
});
This way your code becomes rather short, but still works for any comparable std::pair key.
Code on Ideone

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;
}