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.
Related
I sorry if similar question already exists on this forum, if you could, give me the link.
I have a template class
template<typename type>
class DoublyLinkedList {};
And I want to have Sort method in it.
template<typename type>
class DoublyLinkedList
{
public:
void Sort(){}
};
But list is template so it can contains different types. So how I can create methods for all types that I foresee? I tried in this way:
template<typename type>
class DoublyLinkedList
{
public:
void DoublyLinkedList<int>::Sort(){}
void DoublyLinkedList<string>::Sort(){}
};
But it's wrong. Please help.
The way the standard library generally deals with this problem is to allow users to specify their own compare functions. You can add a templated parameter that users of your type can use to provide a Compare function, like std::sort does. In the implementation of sort, you assume that comparer is a function that compares two elements of the list and returns rather or not the first should be before the second.
#include <string>
template<typename type>
class DoublyLinkedList
{
public:
template<class Comp>
void Sort(Comp comparer);
};
void foo(DoublyLinkedList<std::string> & list)
{
// Sort list by length of strings
list.Sort([](const std::string p_left, const std::string p_right){
return p_left.size() < p_right.size();
});
}
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.
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.
If I define a class using a template such as
template<class K, class V>
class myclass {
...
};
is there a way to pass objects defined by myclass to functions without using a template for the function? In order words, for every function that accepts myclass objects, does it also need to be defined using template< class K, class V> ?
The main reason for this is that I would like define a set of static functions that act on myclass objects so that I may limit the scope of these functions within their cpp files and not in header files.
Make your template class inherit from some base class:
template<class K, class V>
class myclass : mybaseclass { ... };
where the base class declares the public functionality of the template as pure virtual. This way you only have one function rather than one function for each K, V combination.
No, you cannot. A class template is not a class -- it is only a template. Only once you plug in the template parameters do you get a type, and for each different set of parameters you get a different, unrelated type.
Perhaps it's feasible for you to run some sort of type-erasing scheme, whereby you have a single container class which contains an abstract member pointer, and for each type you instantiate a concrete derived object. (Check out Boost.any.)
A bit like this:
class MyClassHolder { };
template <typename K, typename V>
class MyClassConcrete { };
class MyClass
{
MyClassHolder * p;
public:
template <typename K, typename V> init(...) // could be a constructor
{
p = new MyClassConcrete<K, V>();
}
};
Now you can make your function accept a MyClass, but you have to add enough virtual functions to MyClassHolder, implement them in MyClassConcrete and expose them in MyClass that you can realise all your desired semantics.
Yes, if you want your functions to be able to accept any instantiation of your template class they too must be template (typically with the same template parameters that are used for the class).
On the other hand, you can have your template class inherit from a non-template class that still allows you to operate the derived class via virtual functions. Also, to hide the type of your class and avoid riddling all your code of templates, there are the several techniques of type erasure.
No, you will have to make the functions templated as well (unless of course they will be limited to only working with a specific specialization of myclass).
You could do this:
void myfunc(const myclass<int, int>& mc) {}
Only if you wanted to be able to pass any type to your myclass argument in your function, would you need to make that myfunc a template too.
Due to C++'s static nature, you must instantiate a copy of the function for each (K, V) pair in the source since the compiler will have to generate code to access each pair's members differently.
While your reason is not entirely clear to me, yes, each function that takes a myclass as a parameter will also have to be templated on K and V. If you manage to abstract the basics, you could have each myclass< K, V > (which is a different type for each combination of K and V) inherit from a single base class that implements the functionality, or forwards it through virtual functions.
I have a template container class that I derive from called MyContainer. MyContainer defines methods like Get(), Set(), etc. to access individual elements. I'd like to make a bitfield class implemented as a MyContainer<char>, where each char element holds CHAR_BIT number of bits. However, to allow the user to operate on individual bits rather than entire bytes, I would have to make Get() and Set() virtual, which is illegal. What are some alternatives?
I was thinking of defining GetBit() and SetBit() in the derived class, but this would violate the Liskov substitution principle. (Think of a SortMyContainer() function.)
EDIT: Here is a simplified example:
template <typename Datatype>
struct MyContainer
{
virtual Datatype Get();
};
template <typename Datatype> // Error: Templates may not be virtual.
virtual Datatype MyContainer<Datatype>::Get() // EDIT: The problem was on this line. The "virtual" keyword should only appear with the function declaration.
{
// ...
}
It is not illegal, only template virtual member functions are.
// valid
template<typename T> class MyContainer {
virtual void set(const T &) = 0;
}
// not valid
class MyContainer {
template <typename T> virtual void set (const T &) = 0;
}
If I got you wrong, please consider placing a code-sample.
edit after your adding of example code:
template <typename Datatype>
virtual // <-- nope, not here
Datatype MyContainer<Datatype>::Get()
{
// ...
}
virtual is only part of the declaration inside the class body. This should be valid:
template <typename Datatype>
Datatype MyContainer<Datatype>::Get()
{
// ...
}
However, note that the definition must be visible at the point of template instantiation. So either put it in the header-file, too (or in an extra-header that you then include into your real header), or leave it in the class-body.
(please nobody mention exported templates now, you and I know them a lot, but they are not quite a beginner topic, and deprecated with the next standard)
You appear to be confused about what constitutes a template. Class templates may have virtual functions, and indeed, those template parameters may appear in those function's signatures.
template<typename T> class an_interface {
virtual T Get() = 0;
};
class a_class : public an_interface<int> {
};
This is perfectly valid. What's not perfectly valid is
class an_interface {
template<typename T> virtual T Get() = 0;
}
Unless the specific member function in question has it's own, separate template parameters, the member function is not a template and may be virtual, irrespective of if it was generated from a class template.