Is it possible to write a generic variadic zipWith in C++? - c++

I want a generic zipWith function in C++ of variable arity. I have two problems. The first is that I cannot determine the type of the function pointer passed to zipWith. It must be of the same arity as the number of vectors passed to zipWith and it must accept references to the vectors' element types respectively. The second is that I have no idea how to walk these vectors in parallel to build an argument list, call func(), and bail once the shortest vector is exhausted.
template <typename R, typename T, typename... Vargs>
std::vector<R> zipWith (R func(???<what goes here>), std::vector<T> first, Vargs rest) {
???
}

I had a long answer, then I changed my mind in a way that made the solution much shorter. But I'm going to show my thought process and give you both answers!
My first step is to determine the proper signature. I don't understand all of it, but you can treat a parameter pack as a comma-separated list of the actual items with the text-dump hidden. You can extend the list on either side by more comma-separated items! So directly applying that:
template <typename R, typename T, typename... Vargs>
std::vector<R> zipWith (R func(T,Vargs...), std::vector<T> first, Vargs rest) {
???
}
You have to put a "..." after a parameter pack for an expression section to see the expanded list. You have to put one in the regular parameter portion, too:
template <typename R, typename T, typename... Vargs>
std::vector<R> zipWith (R func(T,Vargs...), std::vector<T> first, Vargs... rest) {
???
}
You said that your function parameters are a bunch of vectors. Here, you're hoping that each of Vargs is really a std::vector. Type transformations can be applied to a parameter pack, so why don't we ensure that you have vectors:
template <typename R, typename T, typename... Vargs>
std::vector<R> zipWith (R func(T,Vargs...), std::vector<T> first, std::vector<Vargs> ...rest) {
???
}
Vectors can be huge objects, so let's use const l-value references. Also, we could use std::function so we can use lambda or std::bind expressions:
template <typename R, typename T, typename... Vargs>
std::vector<R> zipWith (std::function<R(T, Vargs...)> func, std::vector<T> const &first, std::vector<Vargs> const &...rest) {
???
}
(I ran into problems here from using std::pow for testing. My compiler wouldn't accept a classic function pointer being converted into a std::function object. So I had to wrap it in a lambda. Maybe I should ask here about that....)
At this point, I reloaded the page and saw one response (by pmr). I don't really understand this zipping, folding, exploding, whatever stuff, so I thought his/her solution was too complicated. So I thought about a more direct solution:
template < typename R, typename T, typename ...MoreTs >
std::vector<R>
zip_with( std::function<R(T,MoreTs...)> func,
const std::vector<T>& first, const std::vector<MoreTs>& ...rest )
{
auto const tuples = rearrange_vectors( first, rest... );
std::vector<R> result;
result.reserve( tuples.size() );
for ( auto const &x : tuples )
result.push_back( evaluate(x, func) );
return result;
}
I would create a vector of tuples, where each tuple was made from plucking corresponding elements from each vector. Then I would create a vector of
evaluation results from passing a tuple and func each time.
The rearrange_vectors has to make table of values in advance (default-constructed) and fill out each entry a sub-object at a time:
template < typename T, typename ...MoreTs >
std::vector<std::tuple<T, MoreTs...>>
rearrange_vectors( const std::vector<T>& first,
const std::vector<MoreTs>& ...rest )
{
decltype(rearrange_vectors(first, rest...))
result( first.size() );
fill_vector_perpendicularly<0>( result, first, rest... );
return result;
}
The first part of the first line lets the function access its own return type without copy-and-paste. The only caveat is that r-value reference parameters must be surrounded by std::forward (or move) so a l-value overload of the recursive call doesn't get chosen by mistake. The function that mutates part of each tuple element has to explicitly take the current index. The index moves up by one during parameter pack peeling:
template < std::size_t, typename ...U >
void fill_vector_perpendicularly( std::vector<std::tuple<U...>>& )
{ }
template < std::size_t I, class Seq, class ...MoreSeqs, typename ...U >
void fill_vector_perpendicularly( std::vector<std::tuple<U...>>&
table, const Seq& first, const MoreSeqs& ...rest )
{
auto t = table.begin();
auto const te = table.end();
for ( auto f = first.begin(), fe = first.end(); (te != t) && (fe
!= f) ; ++t, ++f )
std::get<I>( *t ) = *f;
table.erase( t, te );
fill_vector_perpendicularly<I + 1u>( table, rest... );
}
The table is as long as the shortest input vector, so we have to trim the table whenever the current input vector ends first. (I wish I could mark fe as const within the for block.) I originally had first and rest as std::vector, but I realized I could abstract that out; all I need are types that match the standard (sequence) containers in iteration interface. But now I'm stumped on evaluate:
template < typename R, typename T, typename ...MoreTs >
R evaluate( const std::tuple<T, MoreTs...>& x,
std::function<R(T,MoreTs...)> func )
{
//???
}
I can do individual cases:
template < typename R >
R evaluate( const std::tuple<>& x, std::function<R()> func )
{ return func(); }
template < typename R, typename T >
R evaluate( const std::tuple<T>& x, std::function<R(T)> func )
{ return func( std::get<0>(x) ); }
but I can't generalize it for a recursive case. IIUC, std::tuple doesn't support peeling off the tail (and/or head) as a sub-tuple. Nor does std::bind support currying arguments into a function in piecemeal, and its placeholder system isn't compatible with arbitrary-length parameter packs. I wish I could just list each parameter like I could if I had access to the original input vectors....
...Wait, why don't I do just that?!...
...Well, I never heard of it. I've seen transferring a template parameter pack to the function parameters; I just showed it in zipWith. Can I do it from the function parameter list to the function's internals? (As I'm writing, I now remember seeing it in the member-initialization part of class constructors, for non-static members that are arrays or class types.) Only one way to find out:
template < typename R, typename T, typename ...MoreTs >
std::vector<R>
zip_with( std::function<R(T,MoreTs...)> func, const std::vector<T>&
first, const std::vector<MoreTs>& ...rest )
{
auto const s = minimum_common_size( first, rest... );
decltype(zip_with(func,first,rest...)) result;
result.reserve( s );
for ( std::size_t i = 0 ; i < s ; ++i )
result.push_back( func(first[i], rest[i]...) );
return result;
}
where I'm forced to compute the total number of calls beforehand:
inline std::size_t minimum_common_size() { return 0u; }
template < class SizedSequence >
std::size_t minimum_common_size( const SizedSequence& first )
{ return first.size(); }
template < class Seq, class ...MoreSeqs >
std::size_t
minimum_common_size( const Seq& first, const MoreSeqs& ...rest )
{ return std::min( first.size(), minimum_common_size(rest...) ); }
and sure enough, it worked! Of course, this meant that I over-thought the problem just as bad as the other respondent (in a different way). It also means that I unnecessarily bored you with most of this post. As I wrapped this up, I realized that the replacement of std::vector with generic sequence-container types can be applied in zip_width. And I realized that I could reduce the mandatory one vector to no mandatory vectors:
template < typename R, typename ...T, class ...SizedSequences >
std::vector<R>
zip_with( R func(T...) /*std::function<R(T...)> func*/,
SizedSequences const& ...containers )
{
static_assert( sizeof...(T) == sizeof...(SizedSequences),
"The input and processing lengths don't match." );
auto const s = minimum_common_size( containers... );
decltype( zip_with(func, containers...) ) result;
result.reserve( s );
for ( std::size_t i = 0 ; i < s ; ++i )
result.push_back( func(containers[i]...) );
return result;
}
I added the static_assert as I copied the code here, since I forgot to make sure that the func's argument count and the number of input vectors agree. Now I realize that I can fix the dueling function-pointer vs. std::function object by abstracting both away:
template < typename R, typename Func, class ...SizedSequences >
std::vector<R>
zip_with( Func&& func, SizedSequences&& ...containers )
{
auto const s = minimum_common_size( containers... );
decltype( zip_with<R>(std::forward<Func>(func),
std::forward<SizedSequences>(containers)...) ) result;
result.reserve( s );
for ( std::size_t i = 0 ; i < s ; ++i )
result.push_back( func(containers[i]...) );
return result;
}
Marking a function parameter with an r-value reference is the universal passing method. It handles all kinds of references and const/volatile (cv) qualifications. That's why I switched containers to it. The func could have any structure; it can even be a class object with multiple versions of operator (). Since I'm using r-values for the containers, they'll use the best cv-qualification for element dereferencing, and the function can use that for overload resolution. The recursive "call" to internally determine the result type needs to use std::forward to prevent any "downgrades" to l-value references. It also reveals a flaw in this iteration: I must provide the return type.
I'll fix that, but first I want to explain the STL way. You do not pre-determine a specific container type and return that to the user. You ask for a special object, an output-iterator, that you send the results to. The iterator could be connected to a container, of which the standard provides several varieties. It could be connected to an output stream instead, directly printing the results! The iterator method also relieves me from directly worrying about memory concerns.
#include <algorithm>
#include <cstddef>
#include <iterator>
#include <utility>
#include <vector>
inline std::size_t minimum_common_size() { return 0u; }
template < class SizedSequence >
std::size_t minimum_common_size( const SizedSequence& first )
{ return first.size(); }
template < class Seq, class ...MoreSeqs >
std::size_t minimum_common_size( const Seq& first,
const MoreSeqs& ...rest )
{
return std::min<std::size_t>( first.size(),
minimum_common_size(rest...) );
}
template < typename OutIter, typename Func, class ...SizedSequences >
OutIter
zip_with( OutIter o, Func&& func, SizedSequences&& ...containers )
{
auto const s = minimum_common_size( containers... );
for ( std::size_t i = 0 ; i < s ; ++i )
*o++ = func( containers[i]... );
return o;
}
template < typename Func, class ...SizedSequences >
auto zipWith( Func&& func, SizedSequences&& ...containers )
-> std::vector<decltype( func(containers.front()...) )>
{
using std::forward;
decltype( zipWith(forward<Func>( func ), forward<SizedSequences>(
containers )...) ) result;
#if 1
// `std::vector` is the only standard container with the `reserve`
// member function. Using it saves time when doing multiple small
// inserts, since you'll do reallocation at most (hopefully) once.
// The cost is that `s` is already computed within `zip_with`, but
// we can't get at it. (Remember that most container types
// wouldn't need it.) Change the preprocessor flag to change the
// trade-off.
result.reserve( minimum_common_size(containers...) );
#endif
zip_with( std::back_inserter(result), forward<Func>(func),
forward<SizedSequences>(containers)... );
return result;
}
I copied minimum_common_size here, but explicitly mentioned the result type for the least-base case, proofing against different container types using different size types.
Functions taking an output-iterator usually return iterator after all the iterators are done. This lets you start a new output run (even with a different output function) where you left off. It's not critical for the standard output iterators, since they're all pseudo-iterators. It is important when using a forward-iterator (or above) as an output iterator since they do track position. (Using a forward iterator as an output one is safe as long as the maximum number of transfers doesn't exceed the remaining iteration space.) Some functions put the output iterator at the end of the parameter list, others at the beginning; zip_width must use the latter since parameter packs have to go at the end.
Moving to a suffix return type in zipWith makes every part of the function's signature fair game when computing the return type expression. It also lets me know right away if the computation can't be done due to incompatibilities at compile-time. The std::back_inserter function returns a special output-iterator to the vector that adds elements via the push_back member function.

Here is what I cobbled together:
#include <iostream>
#include <vector>
#include <utility>
template<typename F, typename T, typename Arg>
auto fold(F f, T&& t, Arg&& a)
-> decltype(f(std::forward<T>(t), std::forward<Arg>(a)))
{ return f(std::forward<T>(t), std::forward<Arg>(a)); }
template<typename F, typename T, typename Head, typename... Args>
auto fold(F f, T&& init, Head&& h, Args&&... args)
-> decltype(f(std::forward<T>(init), std::forward<Head>(h)))
{
return fold(f, f(std::forward<T>(init), std::forward<Head>(h)),
std::forward<Args>(args)...);
}
// hack in a fold for void functions
struct ignore {};
// cannot be a lambda, needs to be polymorphic on the iterator type
struct end_or {
template<typename InputIterator>
bool operator()(bool in, const std::pair<InputIterator, InputIterator>& p)
{ return in || p.first == p.second; }
};
// same same but different
struct inc {
template<typename InputIterator>
ignore operator()(ignore, std::pair<InputIterator, InputIterator>& p)
{ p.first++; return ignore(); }
};
template<typename Fun, typename OutputIterator,
typename... InputIterators>
void zipWith(Fun f, OutputIterator out,
std::pair<InputIterators, InputIterators>... inputs) {
if(fold(end_or(), false, inputs...)) return;
while(!fold(end_or(), false, inputs...)) {
*out++ = f( *(inputs.first)... );
fold(inc(), ignore(), inputs...);
}
}
template<typename Fun, typename OutputIterator,
typename InputIterator, typename... Rest>
void transformV(Fun f, OutputIterator out, InputIterator begin, InputIterator end,
Rest... rest)
{
if(begin == end) return ;
while(begin != end) {
*out++ = f(*begin, *(rest)... );
fold(inc2(), ignore(), begin, rest...);
}
}
struct ternary_plus {
template<typename T, typename U, typename V>
auto operator()(const T& t, const U& u, const V& v)
-> decltype( t + u + v) // common type?
{ return t + u + v; }
};
int main()
{
using namespace std;
vector<int> a = {1, 2, 3}, b = {1, 2}, c = {1, 2, 3};
vector<int> out;
zipWith(ternary_plus(), back_inserter(out)
, make_pair(begin(a), end(a))
, make_pair(begin(b), end(b))
, make_pair(begin(c), end(c)));
transformV(ternary_plus(), back_inserter(out),
begin(a), end(a), begin(b), begin(c));
for(auto x : out) {
std::cout << x << std::endl;
}
return 0;
}
This is a slightly improved variant over previous versions. As every
good program should, it starts by defining a left-fold.
It still does not solve the problem of iterators packed in pairs.
In stdlib terms this function would be called transform and would
require that only the length of one sequence is specified and the
others be at least as long. I called it transformV here to avoid
name clashes.

Related

Can type arguments be made deduceable for function templates using std container?

I found this implementation of a few common features of functional programming, e.g. map / reduce:
(I'm aware stuff like that is aparently coming or partially present in new C++ versions)
github link
A part of the code:
template <typename T, typename U>
U foldLeft(const std::vector<T>& data,
const U& initialValue,
const std::function<U(U,T)>& foldFn) {
typedef typename std::vector<T>::const_iterator Iterator;
U accumulator = initialValue;
Iterator end = data.cend();
for (Iterator it = data.cbegin(); it != end; ++it) {
accumulator = foldFn(accumulator, *it);
}
return accumulator;
}
template <typename T, typename U>
std::vector<U> map(const std::vector<T>& data, const std::function<U(T)> mapper) {
std::vector<U> result;
foldLeft<T, std::vector<U>&>(data, result, [mapper] (std::vector<U>& res, T value) -> std::vector<U>& {
res.push_back(mapper(value));
return res;
});
return result;
}
Usage example:
std::vector<int> biggerInts = map<int,int>(test, [] (int num) { return num + 10; });
The type arguments T,U have to be fully qualified for this to compile, as shown in the example, with e.g. map< int,int >( ... ).
This implementation is for C++11, as mentioned on the linked-to page.
Is it possible with newer C++ versions (or even 11) now to make the use of this less verbose, i.e. making the types U,T deduce automatically?
I have googled for that and only found that there is apparently some improvement for class template, as opposed to function template, argument deduction in C++17.
But since I only ever used templates in a rather basic manner, I was wondering whether there is something in existence that I'm not aware of which could improve this implementation verboseness-wise.
You can rewrite map signature to be:
template <typename T, typename M, typename U = decltype(std::declval<M>()(T{}))>
std::vector<U> map(const std::vector<T>& data, const M mapper)
then T will be deduced as value_type of vector's items.
M is any callable object.
U is deduced as return type of M() functor when called for T{}.
Below
std::vector<int> biggerInts = map(test, [] (int num) { return num + 10; });
^^^^ empty template arguments list
works fine.
Live demo
More general templates make template argument deduction easier.
One principle: it is often a mistake to use a std::function as a templated function's parameter. std::function is a type erasure, for use when something needs to store some unknown invokable thing as a specific type. But templates already have the ability to handle any arbitrary invokable type. So if we just use a generic typename FuncT template parameter, it can be deduced for a raw pointer-to-function, a lambda, or another class with operator() directly.
We might as well also get more general and accept any input container instead of just vector, then determine T from it, if it's even directly needed.
So for C++11 I would rewrite these:
// C++20 is adding std::remove_cvref, but it's trivial to implement:
template <typename T>
using remove_cvref_t =
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
template <typename Container, typename U, typename FuncT>
remove_cvref_t<U> foldLeft(
const Container& data,
U&& initialValue,
const FuncT& foldFn) {
remove_cvref_t<U> accumulator = std::forward<U>(initialValue);
for (const auto& elem : data) {
accumulator = foldFn(std::move(accumulator), elem);
}
return accumulator;
}
template <typename Container, typename FuncT>
auto map(const Container& data, const FuncT& mapper)
-> std::vector<remove_cvref_t<decltype(mapper(*std::begin(data)))>>
{
using T = remove_cvref_t<decltype(*std::begin(data))>;
using ResultT = std::vector<remove_cvref_t<decltype(mapper(std::declval<const T&>()))>>;
ResultT result;
foldLeft(data, std::ref(result), [&mapper] (ResultT &res, const T& value) -> ResultT& {
res.push_back(mapper(value));
return res;
});
return result;
}
See the working program on coliru.
There was one unfortunate thing about the old map: it potentially copied the result vector at every iteration. The = in accumulator = foldFn(accumulator, *it); is a self-assignment, which might do nothing, or might allocate new memory, copy contents, then free the old memory and update the container. So instead I've changed the U for foldLeft in this case to a std::reference_wrapper. The = in that case will still "rebind" the wrapper to the same object, but that will at least be quick.
In C++14 and later, you could do away with finding T within map by using a generic lambda: [&mapper] (std::vector<U>& res, const auto& value) ...

templated function argument in C++14

This code does not compile, not even under C++14, because of problems with template type deduction. What is the least inelegant workaround?
#include <vector>
#include <functional>
#include <iostream>
template <class T>
std::vector<T> merge_sorted(
const std::vector<T>& a, const std::vector<T>& b,
std::function<bool(const T, const T)> a_before_b)
{
std::vector<T> ret;
auto ia=a.begin();
auto ib=b.begin();
for (;;ia!=a.end() || ib!=b.end())
ret.push_back( a_before_b(*ia,*ib) ? *(ia++) : *(ib++) );
return ret;
}
int main()
{
std::vector<double> A { 1.1, 1.3, 1.8 };
std::vector<double> B { 2.1, 2.2, 2.4, 2.7 };
auto f = [](const double a, const double b) -> bool {
return (a-(long)(a))<=(b-(long(b))); };
std::vector<double> C = merge_sorted(A, B, f);
for (double c: C)
std::cout << c << std::endl;
// expected outout: 1.1 2.1 2.2 1.3 2.4 2.7 1.8
}
Here the error message from g++ -std=c++14 main.cpp:
main.cpp: In function ‘int main()’:
main.cpp:23:49: error: no matching function for call to ‘merge_sorted(std::vector<double>&, std::vector<double>&, main()::<lambda(double, double)>&)’
std::vector<double> C = merge_sorted(A, B, f);
^
main.cpp:6:16: note: candidate: template<class T> std::vector<T> merge_sorted(const std::vector<T>&, const std::vector<T>&, std::function<bool(T, T)>)
std::vector<T> merge_sorted(
^~~~~~~~~~~~
main.cpp:6:16: note: template argument deduction/substitution failed:
main.cpp:23:49: note: ‘main()::<lambda(double, double)>’ is not derived from ‘std::function<bool(T, T)>’
std::vector<double> C = merge_sorted(A, B, f);
==
Later edit, just for the record: Here comes a version of the code that compiles (thanks to received answers) and that executes correctly (several corrections of the above untested code):
#include <vector>
#include <functional>
#include <iostream>
template <class T, class Pred>
std::vector<T> merge_sorted(const std::vector<T>& a, const std::vector<T>& b, Pred a_before_b)
{
std::vector<T> ret;
auto ia=a.begin();
auto ib=b.begin();
for (;ia!=a.end() && ib!=b.end();)
ret.push_back( a_before_b(*ia,*ib) ? *(ia++) : *(ib++) );
for (;ia!=a.end();)
ret.push_back( *(ia++) );
for (;ib!=b.end();)
ret.push_back( *(ib++) );
return ret;
}
int main()
{
std::vector<double> A { 1.1, 1.3, 1.8 };
std::vector<double> B { 2.1, 2.2, 2.4, 2.7 };
auto f = [](const double a, const double b) -> bool {
return (a-(long)(a))<=(b-(long(b))); };
std::vector<double> C = merge_sorted(A, B, f);
for (double c: C)
std::cout << c << std::endl;
// expected outout: 1.1 2.1 2.2 1.3 2.4 2.7 1.8
}
The problem here is that f is not a std::function. It is some unnamed class type but it is not a std::function. When the compiler does template argument deduction it does not do any conversions, it works with the parameters as is to deduce their type. That means where it expects to see a std::function<bool(const T, const T)> it sees main()::<lambda(double, double)> as that is the type of the lambda and since those types do not match the deduction fails. In order to get deduction to succeed you need to get them to match.
Without changing the function signature you have to cast f to a std::function in order to get it to work. That would look like
std::vector<double> C = merge_sorted(A, B, static_cast<std::function<bool(const double,const double)>>(f));
If you do not mind changing the function signature then we can use
template <class T, class Func>
std::vector<T> merge_sorted(
const std::vector<T>& a, const std::vector<T>& b,
Func a_before_b)
And now it doesn't matter if you pass a std::function or a lambda or a functor.
You need to make the type of a_brefore_b a non-deduced context somehow. I generally introduce a suitably-named helper for this:
template <class T>
struct NonDeduced
{
using type = T;
};
template <class T>
std::vector<T> merge_sorted(
const std::vector<T>& a, const std::vector<T>& b,
typename NonDeduced<std::function<bool(const T, const T)>>>::type a_before_b)
Of course (as #Marc Glisse pointed out in comments), it's quite unnecessary to force use of std::function for the type of a_before_b in the first place. Not to mention the fact that it can easily come with a performance penalty (std::function uses type erasure and dynamic dispatch internally). Just follow what the Standard Library does and type the predicate by a template parameter:
template <class T, class Pred>
std::vector<T> merge_sorted(
const std::vector<T>& a, const std::vector<T>& b,
Pred a_before_b)
The errror comes from the compiler trying to deduce T where it can't deduce T for the std::function parameter which gets passed a lambda.
The standard uses plain template paramters for such predicates for good reasons.
2.1 The predicate is most generic using a template paramter.
You can pass in std::function, std::bind, function pointers, lambdas, functors...
2.2 Inlining (if possible) is most likely to occur.
With a whole bunch of luck a compiler is smart enough to inline a lambda despite being passed "through" a std::function into a template but I wouldn't bet on that. On the contrary, I'd actually expect a compiler to inline a lambda (if suitable) if I pass it via its own type.
Your code has several other issues.
3.1 for (;;ia!=a.end() || ib!=b.end()) here ; is set incorrectly.
3.2 Even with correctly set ; the predicate is wrong since ia!=a.end() || ib!=b.end() will keep the loop running eventhough either ia == a.end() or ib == b.end() is true. Within the loop both iterators are dereferenced to check the predicate which leads us into undefined behaviourland if we are already one past the last element. The loop condition must therefore be for (;ia!=a.end() && ib!=b.end();) which leaves us with elements in either a or b.
Here is what you would probably want to write if you're after performance and generality:
template <class InIt, class OutIt, class Predicate>
auto merge_sorted(InIt first1, InIt last1, InIt first2, InIt last2,
OutIt dest, Predicate pred)
{
// as long as we have elements left in BOTH ranges
for (;first1 != last1 && first2 != last2; ++dest)
{
// check predicate which range offers the lowest value
// and insert it
if (pred(*first1, *first2)) *dest = *(first1++);
else *dest = *(first2++);
}
// here either first1 == last1 or first2 == last2 is true
// thus we can savely copy the "rest" of both ranges
// to dest since we only have elements in one of them left anyway
std::copy(first1, last1, dest);
std::copy(first2, last2, dest);
return pred;
}
Since I can not comment: Generally what #NathanOliver said. A lambda expression can not be "cast" to a std::function, since it is - internally - a different kind of construct.
Of course it would be nice if the compiler could infer (via static analysis) it has to create a std::function object for the lambda. But that doesn't seem to be part of C++11/C++14.
To resolve this, I find it easiest to add a typename to the template:
template <class T, typename F>
std::vector<T> merge_sorted(
const std::vector<T>& a, const std::vector<T>& b,
F& a_before_b)
Of course you can also use class. See question Use 'class' or 'typename' for template parameters? and the old MSDN article here.
Also, note you have a typo in line 13. You probably meant:
for (;;ia!=a.end() || ib!=b.end())

How to implement a subset iterator for a class with N number of vectors in it

If I had a class that holds N number of equally sized vectors. How would I go about implementing a standard iterator template that would iterate between 1 and N number of the vectors together. I wrote a small example demonstrating the problem.
#include <bitset>
#include <tuple>
#include <type_traits>
#include <vector>
//Since std::get<>() for types isn't in c++11, I use this meta-function to determine the index
//of a Type in a list of Types, starting from 0. ex: IndexOf<C, A, B, C>::value = 2
template <typename T, typename... Ts>
struct IndexOf;
template <typename T, typename... Ts>
struct IndexOf<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};
template <typename T, typename U, typename... Ts>
struct IndexOf<T, U, Ts...> : std::integral_constant<std::size_t, 1 + IndexOf<T, Ts...>::value> {};
//Used to determine the slot we're interesting in.
using Handle = const std::size_t;
template<typename... Types>
class DataManager
{
static constexpr std::size_t TypeCount = sizeof... (Types);
using Flags = std::bitset<TypeCount>; //BitMask to determine if the handle has a certain piece of data initialized
std::size_t count, capacity;
std::tuple<std::vector<Types>..., std::vector<Flags>> vectors; //Tuple of vectors, holding the types and flags.
public:
DataManager(std::size_t n) : count(0), capacity(n),
vectors(std::make_tuple(std::vector<Types>(n)..., std::vector<Flags>(n)))
{}
template <typename Type, typename... Args>
void add(Handle handle, Args&&... args) { //Initializes the type in the handle slot of the vector
Flags& flags = std::get<TypeCount>(vectors)[handle]; //Flag the bit, notify that handle
flags.set(IndexOf<Type, Types...>::value); //has that piece of data initialized
std::get<IndexOf<Type, Types...>::value>(vectors)[handle] = Type{ args... };
}
template <typename Type>
Type& get(Handle handle) { //Returns the Type in handle slot of the vector
return std::get<IndexOf<Type, Types...>::value>(vectors)[handle];
}
template <typename Type>
bool has(Handle handle) { //Returns true if the Type is initialized, by checking the bitset
Flags& flags = std::get<TypeCount>(vectors)[handle];
return flags.test(IndexOf<Type, Types...>::value);
}
Handle push_back() {
return count++;
}
};
Which I currently use like this to access data:
//Simple Data
struct D0 { int x, y; };
struct D1 { float n, m; };
struct D2 { int x, y, z; };
int main()
{
DataManager<D0, D1, D2> manager(100);
Handle h0 = manager.push_back();
std::cout << manager.has<D0>(h0) << std::endl; //prints false, h0 doesn't have D0 initialized
manager.add<D0>(h0, 75, 20); //initialize D0 for h0
std::cout << manager.has<D0>(h0) << std::endl; //prints ture, h0 is now initialzed
std::cout << manager.get<D0>(h0).x << std::endl; //prints 75
}
How could I add iterator functionality to the DataManager class, that would only iterate over selected data like this?
int main()
{
...
for (D0 d1, D3 d3 : manager) {
... //Iterate over all D0s and D3s between 0 and count
}
//or
for(DataManager<D0>::iterator it = v.begin(); it != v.end(); ++it {
... //Iterate over just D0s between 0 and count - 10
}
}
Write a range view type. A range view has two iterators, a begin and an end, and exposes .begin() and .end(). Returning a range view of iterators lets you do a for(:) loop without copying anything.
Next you'll want an iterator over the selected elements. I can think of two approaches.
First, a zip iterator. A zip iterator has a tuple of iterators, and it advances them in parallel. When you dereference, it returns a std::tie of the dereference of each iterator.
Second option, a generator iterator. A generator iterator has an index, and a function that maps from the index to some type. ++ and == etc just advance/compare the index. * returns the result of the function call. In this case, you'd return a tie from the function.
I typically impelement a generator iterator by starting with an indexing iterator (that stores an index, and * returns a copy of it), then writing a transform iterator (that stores an iterator, forwards == and ++ and the like to it, stores a function f, and on * does f(*it) where it is the stored iterator). A generator iterator is now just a transform_iterator<F(index_iterator)>.
These are both effectively limited to satisfying the axioms of an input iterator, due to the rules around ::reference type and the like. However, an input iterator is more than enough to do a for(:) loop; what more, a for(:) loop doesn't even need a legal iterator, as it is defined in terms of code not iterator semantics.
The generator/transform iterator is sufficient, and both are useful in other contexts, so I'd go with that approach.
You can choose to type-erase the transformation (into a std::function< T(std::size_t) >) if you want.
template<class T>
using any_generator_iterator = transform_iterator< std::function<T(std::size_t)>( indexing_iterator ) >;
Now to iterate over types A B and C we do:
template<class...Ts,
class R=std::tuple<Ts&...>,
class It=any_generator_iterator<R>
>
range_view< It >
iterate_over() {
auto get = [this](std::size_t i)->R {
return std::tie( this->get<Ts>()... );
};
return { {get, 0}, {{}, count} };
}
elsewhere:
for( auto i : foo.iterate_over<A,B,C>() ) {
auto&& a = std::get<0>(i);
auto&& b = std::get<1>(i);
auto&& c = std::get<2>(i);
// code
}
with a pile of library code on top of it.
Most, if not all, of this has been solved in boost.

.containsKey() method for c++ map

I want to save some repeating work and write a function that mimicks Java
.containsKey() method.
Basically I would like to have something like this:
using namespace std;
map<string,XYclass> mymap;
if (!contains(mymap,"key as string") ) cout << "key not found" << endl;
In C++ one can check, if a map contains key in following way:
m.find(str) != m.end();
I want to write a generic method that returns true if a key is contained in a map.
So far I have following:
template<typename A, typename B> inline bool contains(const std::map< A, B > m, const A& str)
{
return m.find(str) != m.end();
}
which will fail to do template argument deduction, when I run it on a map<string,int> with following call contains(mymap,"key as string"), as "key as string" is actually a char array.
Function works fine when I do explicit instantiation (i.e. by using following call contains<string,int>(mymap,"key as string"))
How to do it properly?
One can exclude parameters from template argument deduction with the below identity trick:
template <typename T>
struct identity { typedef T type; };
template <typename A, typename B>
inline bool contains(const std::map<A, B>& m
, const typename identity<A>::type& str)
{
return m.find(str) != m.end();
}
DEMO
You don't need to specify type template arguments explicitly now.
To be precise, std::map has the total of four type template parameters:
template <typename A, typename B, typename Cmp, typename Alloc>
inline bool contains(const std::map<A, B, Cmp, Alloc>& m
, const typename identity<A>::type& str);
Don't hard-code it to std::map. The expression c.find( k ) != c.end() will work for any container with a find method returning an iterator. The function is applicable to any such types.
As others have noted, std::map has additional template parameters for the comparison function and the node allocator. In principle, listing all its parameters violates the separation of concerns.
template< typename container, typename key >
auto contains( container const & c, key const & k )
-> decltype( c.find( k ) != c.end() )
{ return c.find( k ) != c.end(); }
The decltype specifier performs SFINAE, in case you want other overloads.
I would go for declaring contains() function as template with 3 arguments:
template<typename Key, typename Value, typename Arg>
inline bool map_contains(const std::map< Key, Value > m, const Arg& value)
{
return m.find(value) != m.end();
}
Note, that now Arg must be implicitly convertible to Key. You can easily remove this requirement - all you need to do is to call find() with value explicitly casted to Key type.
Live demo: click.

template argument type deduction from std::function return type with lambda

First of, I'm using C++11 (and my topic sucks).
What I'm trying to do is write a generic template function that implements something usually called sort_by in other programming languages. It involves calculating an arbitrary criterion for each member of a range exactly once and then sorting that range according to those criteria. Such a criterion doesn't have to be a POD, all it has to be is less-than-comparable. For things for which std::less doesn't work the caller should be able to provide her own comparison functor.
I've successfully written said function which uses the following signature:
template< typename Tcriterion
, typename Titer
, typename Tcompare = std::less<Tcriterion>
>
void
sort_by(Titer first, Titer last,
std::function<Tcriterion(typename std::iterator_traits<Titer>::value_type const &)> criterion_maker,
Tcompare comparator = Tcompare()) {
}
It can be used e.g. like this:
struct S { int a; std::string b; double c; };
std::vector<S> s_vec{
{ 42, "hello", 0.5 },
{ 42, "moo!", 1.2 },
{ 23, "fubar", 0.2 },
};
sort_by1< std::pair<int, double> >(
s_vec.begin(), s_vec.end(),
[](S const &one_s) { return std::make_pair(one_s.a, one_s.c); }
);
What I don't like about this approach is that I have to provide the Tcriterion argument myself because the compiler cannot deduce that type from the lambda expression. Therefore this does not work:
sort_by1(s_vec.begin(), s_vec.end(), [](S const &one_s) { return std::make_pair(one_s.a, one_s.c); });
clang 3.1 and gcc 4.7.1 both bark on this (gcc 4.7.1 even barks on the code above, so I guess I'm really doing something wrong here).
However, if I assign the lambda to a std::function first then at least clang 3.1 can deduce the argument, meaning this works:
typedef std::pair<int, double> criterion_type;
std::function<criterion_type(S const &)> criterion_maker = [](S const &one_s) {
return std::make_pair(one_s.a, one_s.c);
};
sort_by1(s_vec.begin(), s_vec.end(), criterion_maker);
So my questions are: How do I have to change my function signature so that I don't need to specify that one argument? And (probably related) how would I fix my example to have it working with gcc?
Don't use std::function in tandem with template argument deduction. In fact, there's very likely no reason to use std::function in a function or function template argument list. More often than not, you should not use std::function; it is a very specialized tool that is very good at solving one particular problem. The rest of the time, you can dispense with it altogether.
In your case you don't need template argument deduction if you use a polymorphic functor to order things:
struct less {
template<typename T, typename U>
auto operator()(T&& t, U&& u) const
-> decltype( std::declval<T>() < std::declval<U>() )
{ return std::forward<T>(t) < std::forward<U>(u); }
// operator< is not appropriate for pointers however
// the Standard defines a 'composite pointer type' that
// would be very helpful here, left as an exercise to implement
template<typename T, typename U>
bool operator()(T* t, U* u) const
{ return std::less<typename std::common_type<T*, U*>::type> {}(t, u); }
};
You can then declare:
template<typename Iter, typename Criterion, typename Comparator = less>
void sort_by(Iter first, Iter last, Criterion crit, Comparator comp = less {});
and comp(*ita, *itb) will do the right thing, as well as comp(crit(*ita), crit(*itb)) or anything else as long as it makes sense.
How about something like this:
template< typename Titer
, typename Tmaker
, typename Tcompare
>
void
sort_by(Titer first, Titer last,
Tmaker criterion_maker,
Tcompare comparator)
{
typedef decltype(criterion_maker(*first)) Tcriterion;
/*
Now that you know the actual type of your criterion,
you can do the real work here
*/
}
The problem is that you can obviously not use a default for the comparator with this, but you can easily overcome that by providing an overload that doesn't take a comparator and fills in std::less internally.
To do it like you originally suggested, the compiler would have to be able to "invert" the template instantiation process. I.e. for a given std::function<> instantiation, what parameter do I have to supply as the result to get it. This "looks" easy, but it is not!
You can use also something like this.
template< typename Titer
, typename Tmaker
, typename TCriterion = typename
std::result_of
<
Tmaker
(
decltype(*std::declval<Titer>())
)
>::type
, typename Tcompare = std::less<TCriterion>
>
void
sort_by(Titer first, Titer last,
Tmaker criterion_maker, Tcompare comparator = Tcompare())
{
}
http://liveworkspace.org/code/0aacc8906ab4102ac62ef0e45a37707d