How to dereference an arbitrary type of container iterator to a certain type in a template function - templates

I want to create a function which takes any kind of container of a certain type and does something with it's elements. Thanks to this, I was able to write a function which takes iterators as templated arguments. However this solution only works for containers, which are directly dereferencable to that certain type like std::vector<SomeObject> or std::deque<SomeObject>. How do I make this function work with std::vector<std::shared_ptr<SomeObject>> or std::map<int, SomeObject> as well? My idea is to let the user provide how to dereference the iterator with a function parameter like std::function<const SomeObject& (Iter)>, where Iter is the template argument of the function.
This is my code:
#include <functional>
#include <iostream>
#include <string>
#include <map>
#include <memory>
class SomeObject {
public:
SomeObject(int id, const std::string& name) : id(id), name(name) {
}
int getId() const {
return id;
}
void doSomething() const {
std::cout << name << std::endl;
}
private:
int id;
std::string name;
};
template <typename Iter>
void doSomethingWithMultipleObjectsInAnArbitraryContainer(Iter begin, Iter end, std::function<const SomeObject& (Iter)> dereferenceIterToObject) {
if (begin == end) {
// The container is empty. Nothing to do...
return;
}
for (Iter it = begin; it != end; ++it) {
const SomeObject& obj = dereferenceIterToObject(it);
// Do something with the object...
obj.doSomething();
}
}
int main(int argc, char** argv) {
SomeObject obj1{1, "one"};
SomeObject obj2{2, "two"};
SomeObject obj3{3, "three"};
std::map<int, SomeObject> mapWithValues {
{obj1.getId(), obj1},
{obj2.getId(), obj2},
{obj3.getId(), obj3}
};
std::map<int, std::shared_ptr<SomeObject>> mapWithPointers {
{obj1.getId(), std::make_shared<SomeObject>(obj1)},
{obj2.getId(), std::make_shared<SomeObject>(obj2)},
{obj3.getId(), std::make_shared<SomeObject>(obj3)}
};
std::vector<SomeObject> vectorWithValues {
obj1,
obj2,
obj3
};
doSomethingWithMultipleObjectsInAnArbitraryContainer(mapWithValues.cbegin(), mapWithValues.cend(),
[](std::map<int, SomeObject>::const_iterator it) -> const SomeObject& {
return it->second;
}); // Compilation error here
doSomethingWithMultipleObjectsInAnArbitraryContainer(mapWithPointers.cbegin(), mapWithPointers.cend(),
[](std::map<int, std::shared_ptr<SomeObject>>::const_iterator it) -> const SomeObject& {
return *it->second;
}); // Compilation error here
doSomethingWithMultipleObjectsInAnArbitraryContainer(vectorWithValues.cbegin(), vectorWithValues.cend(),
[](std::vector<SomeObject>::const_iterator it) -> const SomeObject& {
return *it;
}); // Compilation error here
return 0;
}
Unfortunately, this does not compile. This is the error:
error: no matching function for call to ‘doSomethingWithMultipleObjectsInAnArbitraryContainer(std::map<int, SomeObject>::const_iterator, std::map<int, SomeObject>::const_iterator, main(int, char**)::<lambda(std::map<int, SomeObject>::const_iterator)>)’
});
note: candidate: ‘template void doSomethingWithMultipleObjectsInAnArbitraryContainer(Iter, Iter, std::function<const SomeObject&(Iter)>)’
void doSomethingWithMultipleObjectsInAnArbitraryContainer(Iter begin, Iter end, std::function<const SomeObject& (Iter)> dereferenceIterToObject) {
note: template argument deduction/substitution failed:
test_module/IecTestServer.cpp:131:4: note: ‘main(int, char**)::<lambda(std::map<int, SomeObject>::const_iterator)>’ is not derived from ‘std::function<const SomeObject&(Iter)>’
});
Can I fix this compilation error? If not, do you have any other alternative solution to my problem?

Instead of rewriting your algorithm to accept more complicated iterators, make clients of your algorithm to provide the "simple" iterators to it. If clients have access to c++20 ranges, they can make a transformed range view. If they have access to boost, they can use boost::adaptors::transformed or boost::make_transform_iterator. For example:
std::map<int, SomeObject> mapWithValues {
{obj1.getId(), obj1},
{obj2.getId(), obj2},
{obj3.getId(), obj3}
};
auto get_second = [](const auto& val){ return val.second; };
auto objs_view = mapWithValues | boost::adaptors::transformed( get_second );
doSomethingWithMultipleObjectsInAnArbitraryContainer( objs_view.begin(),objs_view.end() );

With C++20 or Boost <ranges> is the answer. Without, I'm stuck with templates. The trick is to have another template argument which replaces std::function as an argument. If I replace the doSomethingWithMultipleObjectsInAnArbitraryContainer() function with the one below, the example code compiles and works as expected.
template <typename Iter, typename Dereference>
void doSomethingWithMultipleObjectsInAnArbitraryContainer(Iter begin, Iter end, Dereference dereference) {
if (begin == end) {
// The container is empty. Nothing to do...
return;
}
for (Iter it = begin; it != end; ++it) {
const SomeObject& obj = dereference(it);
// Do something with the object...
obj.doSomething();
}
}
Credit to #smitsyn for helping here and to #Erlkoenig for providing the answer to this question.

Related

How to retrieve a boost::variant value for a templated class

I am trying to use the boost::variant in c++11 to create this but I m not sure how.
So I have this structure of the templated class data<>
typedef boost::variant< data<A>,data<B>> dataVar;
stored in a
std::map<string,dataVar> dataMap
It would be great if I could retrieve the type for data somehow so I can assign the values but I have no idea how to make this work elegantly
void registerDataFor(string str)
{
auto itr = dataMap.find(str);
if(itr == dataMap.end())
return;
dataVar = itr->second;
data<v.which()> itemData= boost::get<v.which()>(v);
someArray.push_back(itemData.getIntegerValue());
registerDataFor(itemData.getString());
}
This doesn't compile since the template brackets require a static type.
I ve seen other responses proposing a visitor design but I also need the type for data<> to get the item.
Assuming that both data<A> and data<B> have the same interface, you can use a visitor struct with a template operator():
struct registerImpl : boost::static_visitor<void>
{
template <typename T>
void operator()(T& x) const
{
someArray.push_back(x.getIntegerValue());
registerDataFor(x.getString());
}
};
void registerDataFor(std::string str)
{
auto itr = dataMap.find(str);
if(itr == dataMap.end())
return;
registerImpl visitor;
boost::apply_visitor(visitor, itr->second);
}
wandbox example
In C++14, you can visit the variant in place by using a generic lambda.
void registerDataFor(std::string str)
{
auto itr = dataMap.find(str);
if(itr == dataMap.end())
return;
boost::apply_visitor([](auto& x){
someArray.push_back(x.getIntegerValue());
registerDataFor(x.getString());
}, itr->second);
}
wandbox example
(If you are interested in variant visitation using lambdas and C++14 features, I've written two articles about it: part 1 and part 2.)

Ranged-based for with range_expression returning non-null items from std::vector

Consider the following example:
class Foo {
public:
std::vector<Item*> items = { nullptr, new Item(), new Item(), nullptr };
// function to return all non-nullptr items as an iterator
};
int main() {
Foo foo;
for (Item* i : foo.functionToReturnIteratorOverAllNullItems)
// do something
}
Is it possible to create a function inside the class to return the items in a std::vector also residing in the class, but skipping nullptr items? Or any other items for that matter. I am thinking some lambda function usage would make this work but I am not sure how.
Note I want it to be efficient without re-creating any other new vector and return that. Should preferably work in C++11.
You could use boost::adaptors::filtered (or ranges::view::filter):
// pipe version
for (Item* i : foo.items | filtered([](Item* i){return i;})) {
// ...
}
// function version
for (Item* i : filter(foo.items, [](Item* i){return i;})) {
// ...
}
This is one of the easier range adaptors to write yourself if you want a challenge. You just need an iterator type that does something slightly more complicated than forward along ++ for operator++().
But it's probably easier to just use an if statement, no?
for (Item* i : foo.items) {
// either positive
if (i) {
// ...
}
// or negative
if (!i) continue;
// ...
}
Here's an alternative approach using higher-order functions and lambdas that abstracts the filtering logic. It does not require any additional dependency.
template <typename TContainer, typename TF>
auto for_nonnull_items(TContainer&& container, TF f)
{
for(auto&& i : container)
{
if(i == nullptr) continue;
f(i);
}
return f;
}
std::vector<int*> example{/*...*/};
for_nonnull_items(example, [](auto ptr)
{
// do something with `ptr`
});
By calling for_nonnull_items(this->items, /*...*/) inside foo you can achieve a nicer interface:
foo.for_nonnull_items([](auto ptr)
{
// do something with `ptr`
});
Deriving from std::iterator makes custom iterators fairly trivial. In this case I have implemented a forward_only iterator. Add more features as you see fit.
#include <iterator>
template<class Iter>
struct non_null_forward_iterator : std::iterator<std::forward_iterator_tag, typename Iter::value_type>
{
using value_type = typename Iter::value_type;
non_null_forward_iterator(Iter i, Iter last) : iter_(i), last_(last)
{
seek();
}
value_type operator*() const {
return *iter_;
}
non_null_forward_iterator& operator++() {
++iter_;
seek();
return *this;
}
void seek()
{
while (iter_ != last_) {
if (*iter_)
break;
++iter_;
}
}
bool operator==(const non_null_forward_iterator& r) const {
return iter_ != r.iter_;
}
bool operator!=(const non_null_forward_iterator& r) const {
return iter_ != r.iter_;
}
Iter iter_;
Iter last_;
};
template<class Container>
auto non_null_range(const Container& cont)
{
using underlying_iter_type = typename Container::const_iterator;
using iter_type = non_null_forward_iterator<underlying_iter_type>;
struct X {
iter_type begin() const { return begin_; }
iter_type end() const { return end_; }
iter_type begin_;
iter_type end_;
};
return X {
iter_type(cont.begin(), cont.end()),
iter_type(cont.end(), cont.end())
};
}
struct Item {};
std::ostream& operator<<(std::ostream& os, const Item& item)
{
return std::cout << "an item";
}
int main()
{
std::vector<Item*> items = { nullptr, new Item(), new Item(), nullptr };
for (auto p : non_null_range(items))
{
std::cout << *p << std::endl;
}
}
expected output:
an item
an item
This answer to another SO question provides a solution that works here. The accepted answer to the question does not.
This implements a generic filter helper in C++14.
for( auto ptr: filter([](auto&& x){return x!=nullptr;})( test ) )
will loop over the elements of test such that x!=nullptr.
Doing this in C++11 mostly consists of filling in the return types. The exception is the final filter function, which returns a lambda, which is impossible in C++11, and the use of auto&& in the lambda above.
Many C++11 compilers support auto parameters to lambdas. Those that do not, you can fold the returned lambda of filter and its argument into the filter function itself, and then write out the tedious return value.
C++2x TS has coroutines which make this trivial. The code will look roughly like:
std::generator<Item*> non_null_items() {
for( Item* i : items )
if ( i ) co_return i;
}
as a method within your class.
This mirrors similar C# and python syntax.

How to use implicit type conversion with member functions?

Let us consider the following examples of where implicit type conversion works and where it doesn't:
#include <iostream>
#include <vector>
struct Thingy
{
void write()
{
std::cout << "x" << std::endl;
}
};
struct Node
{
Thingy a;
int data;
operator Thingy&(){return a;}
};
void f(Thingy thingy)
{
thingy.write();
}
template <typename TIterator>
void f (TIterator begin, TIterator end)
{
for (TIterator it = begin; it != end; ++it)
it->write();
}
int main()
{
std::vector<Node> vector(10);
f(vector.begin(), vector.end()); // Doesn't compile
f(vector[3]); // compiles
vector[3].write(); // Doesn't compile
return 0;
}
Why is this so? The
void Node::write();
Should not be fundamentally different from:
void write(Node* this);
Is there any way to make my example code compile and run?
EDIT:
I understand the mechanics of why it doesn't work, I want to understand the philosophy. Why did the C++ Standard committee think it was a bad Idea?
It doesn't work because you never ask the compiler for a conversion when you are doing:
it->write();
I guess it should work with a static_cast:
static_cast<Thingy&>(*it).write();
But I'm barely sure you should simply use:
it->get_a().write();
Or better, as others said, declare a method write in Node.
The implicit conversions can be evil.
Because you can't change the f function, you should just wrap the iterator so it can dereferences a Thingy instead of a Node, if you can use Boost:
#include <iostream>
#include <vector>
#include <boost/iterator/transform_iterator.hpp>
struct Thingy
{
void write()
{
std::cout << "x" << std::endl;
}
};
struct Node
{
Thingy a;
int data;
operator Thingy&(){return a;}
};
void f(Thingy thingy)
{
thingy.write();
}
template <typename TIterator>
void f (TIterator begin, TIterator end)
{
for (TIterator it = begin; it != end; ++it)
it->write();
}
struct Node2Thingy
{
typedef Thingy& result_type;
Thingy& operator()(Node& n) const { return n.a; }
};
int main()
{
std::vector<Node> vector(10);
f(boost::make_transform_iterator(vector.begin(), Node2Thingy()),
boost::make_transform_iterator(vector.end(), Node2Thingy()));
f(vector[3]); // compiles
return 0;
}
Work on g++ 4.8.1 (but surely on older version too).
You tried to resolve your problem by adding an "implicit" indirection, but in that case, it can't work. You can resolve it by adding an explicit indirection.
To answer your question, there is no philosophy behind the scene. It's purely mechanic, the C++ use types that are resolved at compilation time so everything have its type before the execution time. How would you want that the compiler guess that the conversion operator must be called on Node.

Is it possible to set default constructor to `std::map<T1, T2>` values?

So I want to create a simple map std::map<T1, std::string> and I have a function that returns std::string I want somehow to link item creation in std::map with my function so that when my_map[some_new_element] is called my function will be called and its return set to value for some_new_element key. Is such thing possible and how to do it?
You can wrap the map itself or the value type or operator[].
Last wrapper will be the simplest:
template <typename T>
std::string& get_default(std::map<T, std::string>& map, const T& key) {
auto it = map.find(key);
if (it == map.end()) {
return map[key] = create_default_value();
} else {
return *it;
}
}
The value type shouldn't be too hard, either:
struct default_string {
std::string wrapped_string;
default_string() : wrapped_string(create_default_value()) {}
explicit default_string(const std::string& wrapped_string)
: wrapped_string(wrapped_string) {}
operator const std::string&() const { return wrapped_string; }
operator std::string&() { return wrapped_string; }
};
Wrapping map will take a bit more work, as you'd have to duplicate the entire interface, including typedefs. Note: this code is not tested, treat it as proof-of-concept, to steer you in the right direction.
What about a small wrapper class for std::string?
class StringWrapper {
StringWrapper() { //... your code
}
operator std::string&() { return m_string; } // or something like that
private:
std::string m_string;
};
Now you use the following map-type:
std::map<T1, StringWrapper> mymap;
In the constructor of StringWrapper you can define custom actions. It gets called when you insert an item into your map.

How to write a c++ function what can return either iterator or reverse_iterator

As far as I can tell in c++ there is no common base class that covers both iterator and reverse_iterator.
The only suggestion I have seen so far is to get around this using templates (
How to write a function that takes an iterator or collection in a generic way? )
However this solution doesn't seem to work for me.
class MyClass
{
template<typename Iter> Iter* generate_iterator(...params...)
{
//returns either a vector::iterator or vector::reverse_iterator
}
template<typename Iter> void do_stuff(Iter *begin, Iter *end)
{
//does stuff between elements specified by begin and end
//I would like this function to remain agnostic of which direction it is working in!
}
void caller()
{
//I would like this function to remain agnostic of which direction it is working in too...
do_stuff(generate_iterator(blah),generate_iterator(foo));
}
};
In this case, generate_iterator() cannot be used as desired because the compiler complains "generate_iterator is not a member of class MyClass" presumably because I haven't specified it (which I can't in practice as caller should be agnostic of the iterator type).
Can anyone help? Thanks in advance!
edit: as Mark B pointed out generate_iterator must return a pointer - now corrected
update: just started using this http://thbecker.net/free_software_utilities/type_erasure_for_cpp_iterators/start_page.html and it seems to work...
You can create your own iterator class that knows how to go both directions. Encapsulate both types of iterator and internally select whichever one you were initialized with.
Here's a start:
template<typename Container>
class BiIterator
{
public:
BiIterator(Container::iterator i) : m_fwd(i), m_isforward(true) {}
BiIterator(Container::reverse_iterator i) : m_rev(i), m_isforward(false) {}
bool operator==(const BiIterator & left, const BiIterator & right);
Container::value_type & operator*()
{
if (m_isforward)
return *m_fwd;
return *m_rev;
}
const Container::value_type & operator*() const;
BiIterator & operator++()
{
if (m_isforward)
++m_fwd;
else
++m_rev;
return *this;
}
private:
Container::iterator m_fwd;
Container::reverse_iterator m_rev;
bool m_isforward;
};
In C++ you can't write a function that returns two different types. In your template case it will return one or the other depending on the instantiation. You could possibly return a base pointer to a polymorphic iterator but that would cause me to ask what you're really trying to do here. Even the standard containers don't try to do that: They have begin and rbegin to distinguish properly. I would suggest having two separate functions that each do the right thing and return one type of iterator or the other as context dictates.
As a side, note that you can't implicitly determine a template instantiation of a type that's only used for the return type of a function.
By using boost tuple and boost any , your problem can be easily solved. I wrote a example by using boost::any , see below:
#include <boost/any.hpp>
using boost::any_cast;
#define MSG(msg) cout << msg << endl;
boost::any getIterator(std::vector<int>& vec, bool bReverse)
{
if(!bReverse)
return boost::any(vec.begin());
else
return boost::any(vec.rbegin());
}
int main()
{
std::vector<int> myvec;
myvec.push_back(1);
myvec.push_back(2);
myvec.push_back(3);
typedef std::vector<int>::iterator vecIter;
typedef std::vector<int>::reverse_iterator vecRIter;
try
{
boost::any iter = getIterator(myvec, false);
boost::any iter2 = getIterator(myvec, true);
vecIter it1 = any_cast<vecIter>(iter);
vecRIter it2 = any_cast<vecRIter>(iter2);
MSG(*it1);//output 1
MSG(*it2);//output 3
return true;
}
catch(const boost::bad_any_cast &)
{
return false;
}
}
Use boost::variant or boost::any.
boost::variant< reverse_iterator, iterator >
generate_iterator(...) {
if(...) return iterator();
else return reverse_iterator();
}
// user code
boost::variant< reverse_iterator, iterator > v = generate_iterator();
if(reverse_iterator* it = boost::get<reverse_iterator>(v))
...;
else if(...)
...;
Although the variant is better accessed through a visitor.
The downside is that you need some boiler plate to extract the proper type and is exactly the reason why something like any_iterator might be a more sensible choice.