I am interested in implementing a Java-collection-like environment for C++.
I know this isn't a good idea and so on but I don't really want to use it later, but just learn how to do some advanced OOP.
My problem is I want a base class template collection<T> with purely virtual functions. One of these functions should be map() which takes a std::function<R(T)>. Since map() should be virtual I don't know which return type I should use for it. collection<R> isn't possible because member function templates can't be virtual.
How can I add such map() member function for my collection<T> interface?
How can I add such map member function for my collection<T> interface?
The short answer is: you don't. If I have some collection<int> and I want to map std::to_string onto it, I need to produce a collection<std::string>. But a vector_collection<int> needs to produce a vector_collection<std::string> and a list_collection<int> needs to produce a list_collection<std::string> - so that type transformation itself needs to be virtualized. But you can't have virtual member function templates, so there's no way to express this.
In order for this to work, you would have to have a common base type for all of the objects you're putting in your container and then just have a common facade that you could cast between. That is, you really only have collection<unique_ptr<Object>> where map just gives you a different collection<unique_ptr<Object>>, and you just map your collection_facade<int, collection<unique_ptr<Object>>> into a collection_facade<std::string, collection<unique_ptr<Object>>>. With a lot of work and complete disregard for performance and type safety, you could get there.
This is the advantage of templates. If I want to write map for something like vector, I can just write that:
template <class T, class A, class F, class R = std::result_of_t<F(T)>>
std::vector<R, A> map(std::vector<T, A> const& v, F f) {
std::vector<R, A> mapped;
mapped.reserve(v.size());
for (T const& elem : v) {
mapped.push_back(f(elem));
}
return mapped;
}
or:
template <class T, class A, class F, class R = std::result_of_t<F(T)>>
std::vector<R, A> map(std::vector<T, A> const& v, F f) {
return std::vector<R, A>(
boost::make_transform_iterator(v.begin(), f),
boost::make_transform_iterator(v.end(), f)
);
}
I have to implement map() for each container separately - but I would have to do that anyway. And now I'm not giving anything up. Besides, how often are you writing algorithms that are runtime-container-agnostic?
Implement map as an external template function.
For instance, you can decompose map in two stages, internal virtual producer and external templated consumer.
template<typename T> struct Collection {
// virtual T next(); // Java way
// C++ way
// In simplest cases you can rely on iterator pairs.
struct const_iterator {
T const &operator*() const;
const_iterator &operator++();
}
virtual const_iterator begin() const;
virtual const_iterator end() const;
};
template<typename R, typename T> Collection<R> map(
Collection<T> const &coll, std::function<R(T)> const &f);
To implement essentially complicated containers and monadic compositions you can even deny begin() and end() and write an explicit (partial) template specialization.
Related
So, I found it more natural to work in algorithms with collections, not with pair of iterators. So, I wrote some functions like
template <typename R>
void sort(R& range) {
return std::sort(std::begin(range), std::end(range));
}
And to have possibility to work with parts of collections I've wrote following wrapper class, that just holds pair of iterators.
template <typename T>
class Range{
public:
Range(T begin, T end): begin_(begin), end_(end) {}
const T& begin() {
return begin_;
}
const T& end() {
return end_;
}
private:
T begin_, end_;
};
To that point all is fine. Now I want to have function that copies/(moves if possible) its argument and return new collection.
I wrote something like this:
template <typename R>
R sorted(R range) {
sort(range);
return std::move(range);
}
and that's fine except that if I call it with my wrapper Range class internal collection changed. I do understand that with only iterator type it's generally impossible to retrieve the type of collection to create new one, but I want to at least disallow calling it with this Wrapper.
I do understand that I can use static_assert of enable_if to check if it is of particular Range class and I will do that way unless I will find better way. But I want ban it somehow in more general way, so that similar implementation will fail to compile too.
Any ideas?
You can delete the function like:
template <typename T>
void sorted(const Range<T>& range) = delete;
else you can disallow copy and move of the object, so it can only be used with reference
template <typename T>
class Range{
public:
Range(const Range&) = delete;
Range(Range&&) = delete;
Range& operator =(const Range&) = delete;
Range& operator =(Range&&) = delete;
// previous code
};
I would create a traits class called owning_container. By default it considers arguments that are ranges (you should have a traits class/concept constexpr for that -- if begin(x) in a namespace with using std::begin; returns an iterator, call it a range) and have an allocator (another trait) to be owning (as non-owning ranges usually have no need for an allocator) as well as C arrays and std::arrays as owning (via specialization).
This also allows me to detect rvalue owning containers and move their contents in certain contexts (change their iterators into move iterators) without doing the same to non-owning range views.
As mentioned above, a constexpr pseudo-concept might be better than a traits class, or might be useful to augment it.
I'm trying to write LINQ-style methods for my base class Iterator, which List and Sequence will inherit from, but those two containers will have their own implementations of these methods. The "Where" method was pretty straight forward. The "Select" method is very tricky; you can't have virtual template methods.
template <typename T>
class Iterator {
public:
virtual ~Iterator() {};
// This is illegal, but if it weren't, it would be the functionality I want.
template <typename R>
virtual shared_ptr<IIterator<R>> Select(const function<R(T)>& func) = 0;
virtual shared_ptr<IIterator<T>> Where(const function<bool(T)>& func) = 0;
};
"Select" will allow you to transform a Iterator of type "ham sandwich" to a Iterator of type "lettuce" for example.
HamSandwiches->Select<'Lettuce'>([] (shared_ptr<'HamSandwich'> hs) { return hs->Lettuce; });
Ignore the single quotes.
Since we can't have virtual template functions, I would have to, of course, not make the function virtual. In that case, we have a plain old function, which we should never "hide" its implementation by writing implementations in List and Sequence compared to a virtual function; it would be considered a design flaw.
template <typename T>
class Iterator {
public:
virtual ~Iterator() {};
template <typename R>
shared_ptr<Iterator<R>> Select(const function<R(T)>& func);
virtual shared_ptr<Iterator<T>> Where(const function<bool(T)>& func) = 0;
};
template <typename T>
template <typename R>
shared_ptr<Iterator<R>> Iterator<T>::Select(const function<R(T)>& func) {
//Implementation - What would it be?
}
Now we have to have implementation in our base class, which this implementation needs to be somewhat specific for List and Sequence. From what I've seen, you would start to create protected "implementation functions" to do certain actions within the "Select" that could be overriden by List or Sequence.
I'm not looking for an exact answer here, I'm looking for something that would help me get where I may/should want to be. Does anyone spot any common gotchas or things I may be doing wrong to begin with?
Option 1
The ideas I have seen for implementing LINQ in C++ were not relying on virtual methods at all. Instead each result was returned wrapped in a template class, approximately like this:
template <class T>
class RangeWrapper
{
public:
template <class U>
Select(U u) -> decltype(...) {
return RangeWrapper<SelectRange, U>(_myRange, u);
}
private:
T& _myRange;
};
If you chain a few of those, the return type may become quite big, but that's the price to pay to get everything done at compile time.
Option 2
You could implement type erasure to always return an iterator of type Iterator<T>. This should be pretty easy to achieve using a type erased iterator library on the web (there are many, you could have a look at boost.TypeErasure which is accepted but not yet released).
Alternatively you could use any_range in boost, if you're OK to work with ranges (they map to LINQ more naturely than iterators).
Option 3
If you are not doing this as a training exercise, there are several solutions that are already implemented. Use google. Notably, Microsoft itself is working on a C++ Linq to implement the reactive extensions on top of it.
Let's say that I want to implement some classes for containers. All of them should implement such functions like insert, remove etc. So I write some interface:
template <class T>
class ContainerInterface {
public:
virtual void insert(T element) = 0;
template<class Predicate>
virtual void remove(Predicate p) = 0;
};
Now I can write something like:
template <class T>
class MyVector : public ContainerInterface<T>{};
template <class T>
class MyList : public ContainerInterface<T>{};
And I am sure that MyVector and MyList must implement functions insert and remove. However, there is the error:
error: templates may not be ‘virtual’
It comes from:
template<class Predicate>
virtual void remove(Predicate p) = 0;
I don't know the Predicate when I define some container and I dont'see any sense to bind deleter object to container class, for example one time I can pass Predicate to delete integers less than 50 and other time I want delete even integers. What can be done in such case - to declare some templated thing in base class and simulate virtual behaviour of function?
You can use type erasure with function objects. But luckily, the appropriate facilities already exist! For example, in your case, you could use boost::function<bool(const T&)> or std::function<bool(const T&)> (with TR1/C++11 support) as your predicate type!
virtual void remove(std::function<bool(const T&)> p);
Create some abstract class Predicate, which all concrete predicates will have to inherit from. Then, just make the predicate an argument to the function:
virtual void remove(Predicate* p) = 0;
You'll have to make the relevant Predicate member functions virtual of course, and let every concrete implementation override them.
I'm trying to use decltype in the late specified return of a member function in a CRTP base class and it's erroring with: invalid use of incomplete type const struct AnyOp<main()::<lambda(int)> >.
template<class Op>
struct Operation
{
template<class Foo>
auto operator()(const Foo &foo) const ->
typename std::enable_if<is_foo<Foo>::value,
decltype(static_cast<const Op*>(nullptr)->call_with_foo(foo))>::type
{
return static_cast<const Op*>(this)->call_with_foo(foo);
}
};
template<class Functor>
struct AnyOp : Operation<AnyOp<Functor> >
{
explicit AnyOp(Functor func) : func_(func) {}
template<class Foo>
bool call_with_foo(const Foo &foo) const
{
//do whatever
}
private:
Functor func_;
};
I'm basically trying to move all of the sfinae boiler plate into a base class so I don't need to repeat it for every Operation that I create (currently each operation has 6 different calls and there are ~50 operations so there is quite a lot of repetition with the enable_if's).
I've tried a solution which relied on overloading but one of the types which may be passed is anything that's callable(this can be a regular functor from C++03 or a C++0x lambda) which I bound to a std::function, unfortunately, the overhead from std::function, although very minimal, actually makes a difference in this application.
Is there a way to fix what I currently have or is there a better solution all together to solve this problem?
Thanks.
You are, as another answer describes already, trying to access a member of a class in one of the class' base class. That's going to fail because the member is yet undeclared at that point.
When it instantiates the base class, it instantiates all its member declarations, so it needs to know the return type. You can make the return type be dependent on Foo, which makes it delay the computation of the return type until Foo is known. This would change the base class like the following
// ignore<T, U> == identity<T>
template<typename T, typename Ignore>
struct ignore { typedef T type; };
template<class Op>
struct Operation
{
template<class Foo>
auto operator()(const Foo &foo) const ->
typename std::enable_if<is_foo<Foo>::value,
decltype(static_cast<typename ignore<const Op*, Foo>::type>(nullptr)->call_with_foo(foo))>::type
{
return static_cast<const Op*>(this)->call_with_foo(foo);
}
};
This artificially makes the static_cast cast to a type dependent on Foo, so it does not immediately require a complete Op type. Rather, the type needs to be complete when operator() is instantiated with the respective template argument.
You are trying to refer to a member of a class from one of its own base classes, which will fail since the class's body doesn't exist within its base class. Can you pass the logic for computing the return type of call_with_foo as a metafunction to the base class? Is that logic ever going to be complicated?
Another option, depending on how much flexibility you have in changing your class hierarchy (and remember that you have template typedefs), is to have the wrapper inherit from the implementation class rather than the other way around. For example, you can write a AddParensWrapper<T> that inherits from T and has operator() that forwards to T::call_with_foo. That will fix the dependency problem.
I'm trying to make a wrapper to the STL map container, in order to add a const method to return the value given the key. In map, operator[] isn't const, and find() requires dereferencing to get the value (map.find()->second). I'm basing some of my "research" off of Idiomatic C++ for reading from a const map by the way.
The code so far (all inside a single header file):
#include <map>
template <typename K, typename V>
class easymap : public std::map<K, V>
{
//Constructor
easymap() : std::map<K, V>() {};
//The get method
V get(K key)
{
std::map<K, V>::const_iterator iter(find(key));
return iter != end() ? iter->second : V();
}
};
When I try to compile this, I get the following errors:
In member function `V easymap::get(K)':
expected `;' before "iter"
`iter' was not declared in this scope
there are no arguments to `end' that depend on a template parameter, so a declaration of `end' must be available|
(if you use `-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated)
Does how I'm trying to go about doing this make sense? If so, how do I make this work? If not, how would I go about achieving the effect I'm looking for?
Do not derive from std::map. Rather, wrap a std::map instance in your easymap, following the composition before inheritance principle. Besides of all the technical reasons, this reflects the design intent much better: provide a simplified API to map hiding the default one:
template<typename K, typename V>
class easymap {
std::map<K, V> mMap;
public:
V Get(K Key) const {
// ...
}
};
You are missing the template parameters for map, you have to specify typename when declaring the iterator (see here), and for some reason unknown to me (probably a namespace conflict) you have to use this when calling end():
template <typename K, typename V>
class easymap : public std::map<K,V>
{
//Constructor
easymap() : std::map<K, V>() {};
//The get method
V get(K key)
{
typename std::map<K, V>::const_iterator iter(find(key));
return iter != this->end() ? iter->second : V();
}
};
It's no a good idea to use STL container as base class. You should have a really good reason to do that and to be very careful.
The reason is, that none of the STL containers have a virtual destructor. So, if you have a pointer, for example std::map<..> *, that points to your object (that has inherited the map), one of the destructors will not be called. This is a 100% memory leak.
Related question to this one is: Is it okay to inherit implementation from STL containers, rather than delegate?