Searching in the second value of a map i use somthing like the following:
typedef std::map<int, int> CMyList;
static CMyList myList;
template<class t> struct second_equal
{
typename typedef t::mapped_type mapped_type;
typename typedef t::value_type value_type;
second_equal(mapped_type f) : v(f) {};
bool operator()(const value_type &a) { return a.second == v;};
mapped_type v;
};
...
int i = 7;
CMyList::iterator it = std::find_if(myList.begin(), myList.end(),
second_equal<CMyList>(i));
Question: How can i do such a find in a single line without supplying a self written template?
Use a selector to select the first or the second element from the value_type that you get from the map.
Use a binder to bind the value (i) to one of the arguments of the std::equal_to function.
Use a composer to use the output of the selector as the other argument of the equal_to function.
//stl version
CMyList::iterator it = std::find_if(
myList.begin(),
myList.end(),
std::compose1(
std::bind2nd(equal_to<CMyList::mapped_type>(), i),
std::select2nd<CMyList::value_type>())) ;
//Boost.Lambda or Boost.Bind version
CMyList::iterator it = std::find_if(
myList.begin(),
myList.end(),
bind( &CMyList::mapped_type::second, _1)==i);
I am going to be off, voluntarily. The problem with lambda's is that (apart from C++0x) you cannot actually use something like _.second at the moment.
Personally, I thus use:
template <class Second>
class CompareSecond
{
public:
CompareSecond(Second const& t) : m_ref(t) {} // actual impl use Boost.callparams
template <class First>
bool operator()(std::pair<First,Second> const& p) const { return p.second == m_ref; }
private:
Second const& m_ref;
};
Which I combine with:
template <class Second>
CompareSecond<Second> compare_second(Second const& t)
{
return CompareSecond<Second>(t);
}
In order to get automatic type deduction.
And this way I can just write
CMyList::iterator it = std::find_if(myList.begin(), myList.end(), compare_second(i));
True, it does not use binders.
But at least, mine is readable and easily understandable, which beats the crap out of clever trickery in my opinion.
Note:
actually I went as far as wrapping STL algorithms to take full containers, so it would be:
CMyList::iterator it = toolbox::find_if(myList, compare_second(i));
which (imho) is clearly as readable as you can get without the auto keyword for type inference.
You can use Boost Lambda
CMyList::iterator it = std::find_if(
myList.begin(), myList.end(),
boost::lambda::bind(&CMyList::value_type::second, boost::lambda::_1) == i);
You can turn this problem around and just write your own algorithm and use it instead. This way you are not stuck with writing lots of little functors.
template <typename Iter, typename T>
Iter find_second(Iter first, Iter last, T value) {
while (first != last) {
if (first->second == value) {
return first;
}
++first;
}
return first;
}
Note this isn't tested or even compiled.
It seems to me that solving this with binders is just asking for lots of ugly code. What you are really asking for is a new algorithm so just add the algorithm. With that said, I would probably end up implementing something like Matthieu M. came up with.
Related
Below is some code that I would like to:
take a container
take a type
return a new container of the same type containing
objects (ptrs) from the original container that don't match the
type of the compare type
#include <typeinfo>
// Algorithm wrapper around find_if that takes an STL collection and returns
// the subset in that collection not matching the compare. Rely on return-value
// optimization for the returned container.
//
template< template<class, class> class TContainer, class TObject> //, class TCompare>
TContainer FindItemsNotMatching(const TContainer& container) //, TObject object)
{
TContainer found;
auto itemIt = container.begin(), end = container.end();
auto compare = [](const TObject& item) -> bool
{
return typeid(*item) != typeid(TCompare);
};
while (itemIt != end)
{
itemIt = std::find_if(itemIt,
allEntities.end(),
compare);
if (itemIt != end)
{
found.push_back(*itemIt);
}
}
return found;
}
The caller would look hopefully like this:
std::vector<MyType*> vectorFullOfPolymorphicTypes;
std::vector<MyType*> notMatching = FindItemsNotMatching<std::vector<MyType*>, TypeDerivedFromMyType> (vectorFullOfPolymorphicTypes);
Unfortunately, I'm limited to using only Visual Studio 2012 at the moment, so no variadic templates are possible. Any help is appreciated. Here are some errors that I haven't figured out.
UdfAlgorithm.cpp:9: error: C3205: argument list for template template parameter 'TContainer' is missing
No need of template template parameter, just use typename TContainer:
You might change order of template parameter to avoid to provide deducible types.
You might use regular functor to simulate generic lambda (and so avoid to provide extra type), or use value_type from container.
C++11 introduces std::copy_if.
template <class TObject, typename TContainer>
TContainer FindItemsNotMatching(const TContainer& container)
{
TContainer found;
auto predicate = [](const typename TContainer::value_type& item) -> bool
{
return typeid(*item) != typeid(TObject);
};
std::copy_if(container.begin(), container.end(), std::back_inserter(found), predicate);
return found;
}
Usage:
std::vector<MyType*> myypes;
std::vector<MyType*> notMatching = FindItemsNotMatching<SomeDerivedType>(myTypes);
What I want to achieve is a makeSet() function accepting three arguments, a pair of iterator, and a function that transforms the value.
One use case could be creating a set from a sequence of values and do transformation, eg, convert a std::map<K,V> to std::set<std::pair<V,K>>.
The client code may look like
auto s = makeSet(hash.begin(), hash.end(),
[](std::pair<int,int> x) { return std::make_pair(x.second, x.first); });
my current attempt is as follow,
// (commented code are some other *failed* attempt).
template <typename Iterator,
typename T = typename std::iterator_traits<Iterator>::value_type,
template<typename ... > class Monad, typename R >
// typename R, typename Monad = std::function<R(T)> >
std::set<R> makeSet(Iterator first, Iterator last, Monad<R,T> f) {
std::set<R> res;
for (; first != last; ++first) res.insert(f(*first));
return res;
}
but unfortunately does not work. The problem looks like failing to deduce R.
Is there any solution or workaround?
I will be very grateful if you can tell me the right way to do it.
The type of a lambda expression is a unnamed class type (its closure type), not std::function. You cannot therefore deduce std::function or Monad from it.
Your best bet would be to do what the standard library does, and simply accept anything as the predicate:
template <
class Iterator,
class UnaryFunction
>
auto makeSet(Iterator first, Iterator last, UnaryFunction f) -> std::set<decltype(f(*first))>
{
std::set<decltype(f(*first))> res;
for (; first != last; ++first) res.insert(f(*first));
return res;
}
Note that you may have to wrap the decltype in std::remove_reference and/or std::remove_cv to cover all corner cases (or, as suggested by #Yakk, std::decay).
Also, to avoid re-inventing the wheel, you might want to take a look at the Boost.Range library.
"The more you overthink the plumbing, the easier it is to stop up the drain." -- Scotty, Star Trek III.
There's no need to over-design the template function, like that. Just use a forwarding reference, and let your C++17 compiler figure everything out.
#include <set>
#include <map>
#include <utility>
#include <type_traits>
// (commented code are some other *failed* attempt).
template <typename Iterator, typename Lambda>
auto makeSet(Iterator first, Iterator last, Lambda &&f) {
typedef typename std::remove_reference<decltype(first->first)>::type const_first_t;
typedef typename std::remove_const<const_first_t>::type first_t;
typedef typename std::remove_reference<decltype(first->second)>::type second_t;
typedef std::pair<first_t, second_t> R;
std::set<R> res;
for (; first != last; ++first) res.insert(f(*first));
return res;
}
void foo()
{
std::map<int, int> m;
std::set<std::pair<int, int>> s =
makeSet(m.begin(), m.end(),
[](const auto &x)
{
return std::make_pair(x.second, x.first);
});
}
Is it possible to create a template in C++(11) for a function to check whether an object is contained in either a std::vector, std::array or std::list (and possibly even more container types)?
What I have by now:
typedef std::shared_ptr<Tag> SharedTag;
typedef std::vector<SharedTag> TagList;
bool
Tag::isIn(const TagList& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
}
Tag is a normal class. The comparison, of course, should be done t == this, which will be an operator== later on. I did not include this here for simplicity.
So, is it possible to write the upper code only once (without the typedef's though,) for std::vector, std::array, std::list(, maybe for std::set) and so on?
I couldn't find a base-type of all these classes,... which would be my first idea...
Option 1 (good): just use std::find directly:
std::vector<int> v; // populate v however you want
std::vector<int>::const_iterator i = std::find(v.cbegin(), v.cend(), 42);
if (i != v.end()) {
// Now you know 42 is in v
} else {
// Now you know 42 is not in v
}
Option 2 (better): wrap std::find in a helper function:
template <typename Container, typename Value>
bool contains(const Container& c, const Value& v)
{
return std::find(std::begin(c), std::end(c), v) != std::begin(c);
}
// Example usage:
std::vector<int> v; // populate v however you want
if (contains(v, 42)) {
// You now know v contains 42
}
Option 3 (best): use the find method of containers that provide one (which is faster for sorted containers, like set), and std::find for containers that don't provide one:
// If you want to know why I added the int and long parameter,
// see this answer here: http://stackoverflow.com/a/9154394/1287251
template <typename Container, typename Value>
inline auto contains(const Container& c, const Value& v, int) -> decltype(c.find(v), bool()) {
return c.find(v) != std::end(c);
}
template <typename Container, typename Value>
inline bool contains(const Container& c, const Value& v, long) {
return std::find(std::begin(c), std::end(c), v) != std::end(c);
}
template <typename Container, typename Value>
bool contains(const Container& c, const Value& v) {
return contains(c, v, 0);
}
// Example usage:
std::set<int> s; // populate s however you want
if (contains(s, 42)) {
// You now know s contains 42
}
Of course, you could write std::find yourself, but you might as well use it.
You may use template:
typedef std::shared_ptr<Tag> SharedTag;
template <typename Container>
bool Tag::isIn(const Container& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
}
That requires that Container is a container of something convertible to SharedTag.
There is no common base-type between those containers. That's just not the way the STL library works, it is based on templates and generic programming principles.
So, if you want to implement the function once for all containers, you would have to make it a template. Here is a basic form:
template <typename TagContainer>
bool Tag::isIn(const TagContainer& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
};
But this has the problem that you could technically pass anything to this function that isn't actually a container of SharedTag, so, to solve this issue, you could use a trick called Sfinae to enforce that rule:
template <typename TagContainer>
typename std::enable_if< std::is_same< SharedTag, typename TagContainer::value_type >::value,
bool >::type Tag::isIn(const TagContainer& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
};
Which kind of ugly, but it works.
There is still one problem though. I suspect that your Tag class is a normal non-template class, which means that you are probably implementing it in a cpp file, but templates need to be implemented in the header file (because function templates need to have their implementation visible to the compiler to generate a new concrete version of it for each type that you call it with).
One way to avoid this problem is to provide a number of overloaded non-template functions for each container you want to support, and then, under-the-hood, you call a local function template, and in this case, you don't need the sfinae trick to constrain it, since it is already limited to the set of overloads that you provided. Something like this:
template <typename TagContainer>
bool Tag::isIn_impl(const TagContainer& lst) {
return std::any_of(lst.begin(), lst.end(), [this](const SharedTag& t) {
return t->name == this->name;
});
};
bool Tag::isIn(const std::list<SharedTag>& lst) {
return isIn_impl(lst);
};
bool Tag::isIn(const std::vector<SharedTag>& lst) {
return isIn_impl(lst);
};
bool Tag::isIn(const std::set<SharedTag>& lst) {
return isIn_impl(lst);
};
Note that the isIn_impl is a member function template that should be declared in the header file, in the private section of the class, and can safely be defined in the cpp file, because that cpp file is the only place where that function template is called from.
The obvious issue with that solution is that you have to manually provide every overload that you want to support, which means that it isn't very "scalable" in the future, but in real-life, there probably aren't that many containers that you'd want to support. If you want the full generality, you really have to use the template approach (unless you want to do type-erasure on the container... but that's a bit beyond the scope of what I'm willing to explain here).
You can use a nested variadic template to achieve this. Here is a handy demo: note the magic part, template <template <typename...> class V, typename E>. A variadic template is necessary because vector, list &co. all have a different number of template parameters (allocator, comparator etc.) for which a default value is supplied by the STL.
#include <vector>
#include <string>
#include <memory>
#include <algorithm>
#include <list>
#include <set>
#include <iostream>
class Tag {
public:
Tag(const std::string &n): name(n) {}
template <template <typename...> class V, typename E>
bool isIn(const V<E> &lst) {
return std::any_of(lst.begin(), lst.end(), [this](const E &t) {
return t.name == this->name;
});
}
private:
std::string name;
};
typedef std::shared_ptr<Tag> SharedTag;
typedef std::vector<SharedTag> TagList;
int main() {
Tag t("foo");
// Set needs some extra bits to work (a `<` operator etc.)
//std::set<Tag> a = {Tag("foo"), Tag("bar")};
std::vector<Tag> b = {Tag("foo"), Tag("bar")};
std::list<Tag> c = {Tag("foo"), Tag("bar")};
//std::cout << t.isIn(a) << std::endl;
std::cout << t.isIn(b) << std::endl;
std::cout << t.isIn(c) << std::endl;
}
I always try to use STL-like algorithms when possible, as they are concise and very expressive.
I have this code in one of my libraries:
auto& findFlag(const std::string& mName)
{
for(auto& f : makeRangeCastRef<Flag>(getFlags()))
if(f.hasName(mName))
return f;
throw Exception::createFlagNotFound(mName, getNamesStr());
}
I would like to write it in a modern C++ algorithmic form, but I can't figure out how to deal with the early return and the possible throw.
for(auto& value : container) if(predicate(value)) return value;
// ^~~~~~
// IMPORTANT: return from the caller function, not the algorithm itself
Ideally I'd like to write the real code snippet as:
auto& findFlag(const std::string& mName)
{
early_return_if(makeRangeCastRef<Flag>(getFlags()),
[&mName](const auto& f){ return f.hasName(mName); });
throw Exception::createFlagNotFound(mName, getNamesStr());
}
Obviously, something like early_return_if cannot exist - there is no way, as far as I know, to call return on the caller function from a callee. return early_return_if(...) could work, but then I can't throw the exception without creating a specific algorithm that throws exceptions.
What do you suggest? Should the keep the code as it is or is there any algorithm-like way I can re-write it?
EDIT:
As mentioned in the comments, std::find_if is a good candidate, but there is an unnecessary check that can be avoided:
auto& findFlag(const std::string& mName)
{
auto container(makeRangeCastRef<Flag>(getFlags())); // Need to write this out...
// Need to keep track of the returned iterator...
auto it(findIf(container, [&mName](const auto& f){ return f.hasName(mName); }));
if(it != container.end()) return *it; // I don't like this either...
throw Exception::createFlagNotFound(mName, getNamesStr());
}
A range-based algorithm that uses boost::optional. reference_type_t left as an exercise (hint: write iterator_type_t first based off of adl-lookup of begin on a range).
template<class Range, class Function>
boost::optional< reference_type_t<Range> >
search_if( Range&& r, Function&& f ) {
for( auto&& x:std::forward<Range>(r) ) {
if (f(x))
return std::forward<decltype(x)>(x);
}
return {};
}
Then:
auto& findFlag(const std::string& mName) {
auto result = search_if(
makeRangeCastRef<Flag>(getFlags()),
[&](auto&& f){return f.hasName(mName); }
);
if (result) return *result;
throw Exception::createFlagNotFound(mName, getNamesStr());
}
you could do away with the exception entirely, and have findFlag return an optional itself (which basically makes it search_if).
And no, you cannot inject flow control into the function that calls you.
The above does rely on an optional that supports optional references. These are controversial: the upcoming std::optional did not support them last I checked.
You can also replace such optionals with simple T*s.
template<class Range, class Function>
value_type_t<Range>*
search_if( Range&& r, Function&& f ) {
for( auto&& x:std::forward<Range>(r) ) {
if (f(x))
return &x;
}
return nullptr;
}
but a downside is that if your range is strange (like std::vector<bool>), you'll end up with a reference to a temporary above.
A sketch of value_type_t and reference_type_t, which take a range/container and output that range/containers value/reference type:
namespace adl_aux {
using std::begin;
template<class R> using iterator_t = decltype( begin(std::declval<R>()) );
}
using adl_aux iterator_t;
template<class T>struct void{using type=void;}
template<class T>using void_t=typename void<T>::type;
template<class R,class=void>
struct value_type {};
template<class R>
struct value_type<R, void_t< iterator_t<R> > {
using type = std::iterator_traits< iterator_t<R> >::value_type;
};
template<class R>using value_type_t = typename value_type<R>::type;
template<class R,class=void>
struct reference_type {};
template<class R>
struct reference_type<R, void_t< iterator_t<R> > {
using type = std::iterator_traits< iterator_t<R> >::reference_type;
};
template<class R>using reference_type_t = typename reference_type<R>::type;
it can be made more robust -- the SFINAE check on iterators can check iterator axioms on the return type of begin, and ensure that end is either an identical iterator or a compatible sentinal.
I decided that using the loop is the most expressive and generally best solution for this particular case.
I'm not sure what exactly makeRangeCastRef<>() and some of your other code is doing but personally I think the find_if version is more readable than your original version if you write it more like this:
auto& findFlag(const std::string& mName)
{
auto findIt = find_if(cbegin(getFlags()), cend(getFlags()), [&](const auto& f){ return f.hasName(mName); });
if (findIt == container.end()) throw Exception::createFlagNotFound(mName, getNamesStr());
return *findIt;
}
It seems more natural to me to check for the exceptional condition (flag not found) and throw an exception, otherwise fall through to the normal exit path of returning the found item, rather than in your loop based version returning from inside the loop in the 'normal' condition, and otherwise falling through to throw an exception.
Using Alexandrescu's Expected<T> you can write an algorithm that returns an object convertible to the element you are looking for or throws an exception if it wasn't found. Something like (didn't compile this):
template <class It, class Pred, class Else>
Expexted<T&> find_if_ref(It first, It last, Pred pred, Else el)
{
auto it = find_if(first, last, pred);
if (it == last) {
try {
el();
}
catch (...) {
return std::current_exception();
}
}
return *it;
}
What I am trying to do:
I have a simple set union function in C++ using STL, and I'm trying to wrap it in a function that will let me perform the union of arbitrarily many sets contained in STL data structures (e.g. std::list, std::vector, std::forward_list, ...).
How I tried to do it:
To start, my simple set union:
#include <algorithm>
template <typename set_type>
set_type sunion(const set_type & lhs, const set_type & rhs)
{
set_type result;
std::set_union( lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), std::inserter(result, result.end()) );
return result;
}
where set_type defines some STL std::set<T>, e.g. std::set<int>.
After noticing several times that I end up needing to perform several unions on iterators of sets (in Python this would be a reduce of my sunion function over some iterable object of set_types). For instance, I might have
std::vector<std::set<int> > all_sets;
or
std::list<std::set<int> > all_sets;
etc., and I want to get the union of all sets in all_sets. I am trying to implement a simple reduce for this, which essentially does a (faster, more elegant, non-copying) version of:
sunion(... sunion( sunion( all_sets.begin(), all_sets.begin()+1 ), all_sets.begin()+2 ) , ... )
Essentially, to do this quickly, I just want to declare a set_type result and then iterate through all_sets and insert value in every set in all_sets into the result object:
template <typename set_type>
set_type sunion_over_iterator_range(const std::iterator<std::forward_iterator_tag, set_type> & begin, const std::iterator<std::forward_iterator_tag, set_type> & end)
{
set_type result;
for (std::iterator<std::forward_iterator_tag, set_type> iter = begin; iter != end; iter++)
{
insert_all(result, *iter);
}
return result;
}
where insert_all is defined:
// |= operator; faster than making a copy and performing union
template <typename set_type>
void insert_all(set_type & lhs, const set_type & rhs)
{
for (typename set_type::iterator iter = rhs.begin(); iter != rhs.end(); iter++)
{
lhs.insert(*iter);
}
}
How it didn't work:
Unfortunately, my sunion_over_iterator_range(...) doesn't work with arguments std::vector<set_type>::begin(), std::vector<set_type>::end(), which are of type std::vector<set_type>::iterator. I thought std::vector<T>::iterator returns an iterator<random_access_iterator_tag, T>. A
After compilation failed because of type incompatibility of the iterators, I looked at the stl vector source (located in /usr/include/c++/4.6/bits/stl_vector.h for g++ 4.6 & Ubuntu 11.10), and was surprised to see the typedef for vector<T>::iterator to be typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator;. I had thought that a ForwardIterator was a subtype of RandomAccessIterator, and so should be fine, but clearly I was incorrect, or I would not be here.
How I am grateful and ashamed of inciting your frustration due to my inexperience:
Apologies if I'm showing my ignorance-- I am trying to learn to be a better object oriented programmer (in the past I have simply hacked everything out in C-style code).
I'm doing my best, coach! Please help me out and spare the world from bad code that I would produce without your code ninja insight...
Here's a very naive approach:
std::set<T> result;
std::vector<std::set<T>> all_sets;
for (std::set<T> & s : all_sets)
{
result.insert(std::make_move_iterator(s.begin()),
std::make_move_iterator(s.end()));
}
This invalidates the elements in the source sets, though it doesn't actually move the element nodes over. If you want to leave the source sets intact, just remove the make_move_iterator.
Unfortunately there's no interface for std::set that lets you "splice" two sets in a way that doesn't reallocate the internal tree nodes, so this is more or less as good as you can get.
Here's a variadic template approach:
template <typename RSet> void union(RSet &) { }
template <typename RSet, typename ASet, typename ...Rest>
void union(RSet & result, ASet const & a, Rest const &... r)
{
a.insert(a.begin(), a.end());
union(result, r...);
}
Usage:
std::set<T> result
union(result, s1, s2, s3, s4);
(Similar move-optimizations are feasible here; you can even add some branching that will copy from immutables but move from mutables, or from rvalues only, if you like.)
Here's a version using std::accumulate:
std::set<T> result =
std::accumulate(all_sets.begin(), all_sets.end(), std::set<T>(),
[](std::set<T> & s, std::set<T> const & t)
{ s.insert(t.begin(), t.end()); return s; } );
This version seems to rely on return value optimisation a lot, though, so you might like to compare it to this hacked up and rather ugly version:
std::set<T> result;
std::accumulate(all_sets.begin(), all_sets.end(), 0,
[&result](int, std::set<T> const & t)
{ result.insert(t.begin(), t.end()); return 0; } );
Usually, when using iterators we don't care about the actual category. Just let the implementation sort it out. That means, just change the function to accept any type:
template <typename T>
typename std::iterator_traits<T>::value_type sunion_over_iterator_range(T begin, T end)
{
typename std::iterator_traits<T>::value_type result;
for (T iter = begin; iter != end; ++ iter)
{
insert_all(result, *iter);
}
return result;
}
Note that I have used typename std::iterator_traits<T>::value_type, which is the type of *iter.
BTW, the iterator pattern is not related to OOP. (That doesn't mean it's a bad thing).