I'm trying to understand how templates work, and I've come up with this problem. Now, I'm perfectly aware that it can be solved using polymorphism, but I'm curious to see if it can be solved by just using templates. The situation is as follows:
Suppose I have two types of queues, which are defined as follows:
#include <queue>
template <typename GenType, typename Comparator>
class Priority
{
public:
Priority()
{ }
~Priority()
{ }
void insert(GenType const& t)
{ mQueue.push(t); }
private:
std::priority_queue<GenType, std::vector<GenType>, Comparator> mQueue;
};
template<typename GenType>
class FIFO
{
public:
FIFO()
{ }
~FIFO()
{ }
void insert(GenType const& t)
{ mList.push_front(t); }
private:
std::deque<GenType> mList;
};
And now, I have a class that can use either Queue or FIFO (or any other type of queue) as shown here:
// I'm not sure that this is how it should be declared...
template <typename GenType,
template<typename, typename...> class List>
class User
{
public:
User()
{ }
~User()
{ }
void add(GenType const& t)
{ mList.insert(t); }
private:
// This line gives an error.
List mList;
};
As it stands, the marked line gives an error, which I understand since I haven't actually passed any template parameters to List. The thing is that I don't know how to solve this error.
To give some context, the use case for this was to be able to have the User class take a any type of queue and could be used like this:
User<int, FIFO> u1;
// Not sure if it is this way:
User<int, Priority, std::less<int>> u2;
// Or this way:
User<int, Priority, std::less> u2;
Any suggestions on how to solve this problem?
Don't do it that way.
Instead, let your User class template take the full type of the container it's going to use, and let the container indicate what type of values it takes:
template <typename Container>
class User
{
public:
using value_type = typename Container::value_type; // you'll have to add this
// typedef to your containers
User() = default;
~User() = default;
void add(value_type const& t)
{
mList.insert(t);
}
private:
Container mList;
};
This way, I, as the user of your class template, can provide the right thing. If I want to use your priority queue, I can pass in the comparator I want directly:
User<Priority<int, std::less<>>> u;
Or not:
User<FIFO<int>> u2;
Or maybe I wrote my own container which isn't even a class template:
User<SpecialContainer> u3;
Yours works either way. Generic is good.
There is already an accepted answer, but I'd like to show the desired syntax.
private:
// This line doesn't give an error.
List<GenType> mList;
};
Now this line compiles too:
User<int, FIFO> u1;
The last two lines can't be compiled because the template User accepts only two parameters. Just add a third parameter.
Related
I want to implement a custom queue class so I have done most of the work but I have a problem I want to implement casting of the type of the queue elements. Below it my code so
I am stuck how to continue implementing the casting as it should cast the elements of the queue to another type using static_cast
template<typename T, int N>
class Queue
{
private:
std::vector<T> elems;
public:
<return type> cast(void) {}
}
You could implement it as a member template although that would be somewhat annoying in contexts where it becomes a dependent name (it look as if you have a ring buffer; to keep things simple I'm using a std::deque instead):
template <typename T, int N>
class Queue {
//
std::deque<T> elems;
public:
template <typename O>
O cast() { return static_cast<O>(this->elems.back()); }
};
template <typename Q>
void f(Q& q) {
q.template cast<int>(); // "template" needed because it is a dependent name
}
int main() {
Queue<short> q;
// ...
q.cast<int>(); // doesn't need this annoying extra "template"
}
The way to avoid the necessity of the template in a dependent context is to not use a member function. I'd just define a friend function inside the Queue definition:
template <typename O>
friend O cast(Queue& q){ return static_cast<O>(q.back()); }
// ...
cast<int>(q);
To see it live use the Compiler Explorer link.
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();
});
}
unfortunately my actual template is too full of stuff that is unrelated to my question, so i tried to put everything in a short example. Lets say, I have written the following template:
#include <vector>
template <typename T> class MyTemplate{
public:
typedef void(*MyFunc)(T);
void addFunc(MyFunc f){myFuncs.push_back(f);}
void callFuncs(T value){
for (std::size_t i=0;i<myFuncs.size();i++){myFuncs[i](value);}
}
private:
std::vector<MyFunc> myFuncs;
};
I learned already, that I can specialize this template to behave different when the passed type is a vector, so I wrote this:
template <typename T> class MyTemplate<std::vector<T> > {
public:
typedef void(*MySingleElementFunc)(T);
void addSingleElementFunc(MySingleElementFunc f){
this->mySingleElementFuncs.push_back(f);
}
void callFuncs(std::vector<T> value){
//for (std::size_t i=0;i<myFuncs.size();i++){
// myFuncs[i](value);
//}
for (std::size_t i=0;i<mySingleElementFuncs.size();i++){
for (int size_t i=0;i<value.size();i++){
mySingleElemetnFuncs[i](value[i]);
}
}
}
private:
std::vector<MySingleElementFunc> mySingleElementFuncs;
};
Now my question is, what is the most elegant way (if possible without inheritance) not only to specialize the template for the case of vector< T > but at the same time still being able to use the first templates methods where vector< T > is the template parameter. What I would like to do later is the following
void Func1(int i){}
void Func2(std::vector<int> i){}
MyTemplate<std::vector<int> > myTemplate;
myTemplate.addFunc(Func1);
myTemplate.addFunc(Func2);
Is it possible to achieve this without simply copy&paste all stuff I need from the original template, to do the same also with the specialized version? I guess I will have to use some kind of inheritance. However, I want to avoid something like this:
MyTemplate<std::vector<int> > myTemplate;
// myTemplate.addFunc(Func1); // does not work
myTemplate.addFunc(Func2);
MyVectorTemplate<std::vector<int> > myVectorTemplate;
myVectorTemplate.addFunc(Func1); // works
myVectorTemplate.addFunc(Func2);
i.e. the functionality should be determined only by the type passed to the template but not by choosing the appropriate subclass. Anyhow, I have to admit that I am a bit confused about how to inherit in this case. If it was not a template, I could write something like
class MyVectorClass : public MySingleObjectClass {}
However, the following does not make any sense:
template <typename T> MyTemplate<std::vector<T> > : public MyTemplate<std::vector<T> >
but in some sense, this is what I would like to have.
I am sorry for such a long post and I hope it is more or less clear what is my problem...
EDIT: I just found a mistake in the above code. The loop in the vector template should read
for (std::size_t i=0;i<mySingleElementFuncs.size();i++){
for (int size_t j=0;j<value.size();j++){
mySingleElemetnFuncs[i](value[j]);
}
}
i.e. each registered function should be called once for each entry in the vector. (Otherwise the template does not work if the number of registered functions is not equal to the size of the vector.)
In fact you want add functionality to the specialization, something like:
template <typename T> class MyTemplate<std::vector<T> >
{
public:
typedef void(*MySingleElementFunc)(T);
typedef void(*MyVectorFunc)(std::vector<T>);
void addSingleElementFunc(MyVectorFuncf){
this->myVcetorFuncs.push_back(f);
}
void addSingleElementFunc(MySingleElementFunc f){
this->mySingleElementFuncs.push_back(f);
}
void callFuncs(const std::vector<T>& value){
for (std::size_t i=0;i<myVectorFuncs.size();i++){
myVectorFuncs[i](value);
}
for (std::size_t i=0;i<mySingleElementFuncs.size();i++){
for (int size_t i=0;i<value.size();i++){
mySingleElemetnFuncs[i](value[i]);
}
}
}
private:
std::vector<MySingleElementFunc> mySingleElementFuncs;
std::vector<MyVectorFunc> myVectorFuncs;
};
template <typename T>
class MyTemplateBase {
// generic stuff goes here
};
template <typename T>
class MyTemplate : public MyTemplateBase<T> {
// nothing goes here
};
template <typename T>
class MyTemplate<std::vector<T>> : public MyTemplateBase <std::vector<T>> {
// specialized stuff goes here
}
If you don't want public inheritance you can use private inheritance, but then you would have to explicitly export everything inherited privately:
template <typename T>
class MyTemplate<std::vector<T>> : private MyTemplateBase <std::vector<T>> {
public:
// generic stuff re-exported
using MyTemplateBase<std::vector<T>>::Func1;
using MyTemplateBase<std::vector<T>>::Func2;
// specialized stuff goes here
}
Might still be worth it, as public inheritance is not exactly the most appropriate tool for code reuse.
I think that, since Vector is a template not a class, should be something like:
template<template <typename ...> class T /*= std::vector*/>
class SomeClass
{
T x;
};
using namespace std;
#include <vector>
#include <string>
template <class T>
struct ValNode {
string id;
T value;
};
class ValTable {
public:
ValTable();
template <class T>
void add(string,T);
const bool find(string);
void remove(string);
private:
template<class T>
std::vector<ValNode<T>*> vals;
};
complier error:error: data member 'vals' cannot be a member template
i did try to use T* value in the struct, but i didnt work out.
I didnt use any of the functions in codes yet. was just trying to compling it into *.o file (with .cpp file also).
As the error says, variables (including data members) can't be templates; only classes and functions can be.
It looks like you want the table to be able to hold values of various different types, specified at run-time according to which types are passed to add(). For that, you need dynamic types, which aren't directly supported in C++. You might consider libraries like Boost.Any or Boost.Variant for that.
On the other hand, maybe you just want to store a single type in each table, and different types in different tables. In that case, the class itself will need to be a template:
template <typename T>
class ValTable {
public:
ValTable();
void add(string,T);
const bool find(string);
void remove(string);
private:
std::vector<ValNode<T>*> vals;
};
In C++ you can have template methods in a class, but not template data members.
For example:
template<typename T, int n>
struct FixedVector {
T x[n];
FixedVector() {
for (int i=0; i<n; i++) x[i] = 0;
}
template<typename C>
void copy(const C& container) {
if (container.size() != n) {
throw std::runtime_error("Wrong size");
}
int j = 0;
for (typename C::const_iterator i=container.begin(),
e=container.end();
i!=e;
++i)
{
x[j++] = *i;
}
}
};
With the above class you can declare FixedVector<int, 5> f and call f.copy(v) where v can be for example a vector or a list or anything that has size begin and end.
So FixedVector::copy is a template method and this means that the compiler will generate a different version of it for each different type you will pass to the function.
std::vector<double> y;
y.push_back(3.4); y.push_back(5.6); y.push_back(7.8);
std::list<unsigned char> z;
z.push_back('a'); z.push_back('b'); z.push_back('c');
FixedVector<int, 3> v;
v.copy(y); // This is ok
v.copy(z); // This is ok too
C++ doesn't allow template data members because this would imply a different class size depending on how many types you are using in a specific compilation unit and this doesn't go with the C++ compilation model of one-unit-at-a-time.
Adding methods is instead fine because it doesn't affect class size, and everything can be fixed at link time by avoiding pulling multiple copies of the same method from different compilation units.
You will have to declare ValTable as template
template <class T>
class ValTable{
public:
ValTable();
//template <class T>
void add(string,T);
const bool find(string);
void remove(string);
private:
//template<class T>
std::vector<ValNode<T>*> vals;
};
You won't be able to do that ValTable needs to be a template
You can have this :
template <class T> //Make the class as template
class ValTable {
public:
ValTable();
template <class X>
void add(string,X);
const bool find(string);
void remove(string);
private:
//template<class T>
std::vector<ValNode<T>*> vals;
};
You cannot have template member values: each translation unit could access different instantiations resulting in different ibject layouts. You'd need to factor out the type in some way.
The standard library does something along the lines of what you want for std::locale: each std::locale stores a collection of differently typed objects. It is soecial purpose and can't be used for your purpose directly.
The basic idea is to automatically map each type used to an int which is then used to map the type to an instance. The vals member would then be a function template looking up the correct instance. A rough outline could look like this:
int type_index_alloc() {
static std::atomic<int> current(0);
return ++current;
}
template <typename T>
int type_map() {
static int rc = type_index_alloc();
}
class container {
struct base { virtual ~base() {} };
template <typename T>
struct value: base { T v; };
std::map<int, std::shared_ptr<base>> vals_;
public:
T& vals() {
std::shared_ptr<base>& rc(vals_[type_map<T>()]);
if (!rc) {
rc = std::make_shared<value<T>>()); }
return static_cast<value<T>&>(*rc).v;
}
};
This a just trying to show how things are being set up: I currently don't have access to a compiler. Also, the code example just provides access to an object of type T but it could easily be changed to use a std::vector<T> instead.
I recently saw some code using macros like
#define CONTAINS(Class, Name)\
private:\
std::list<Class> m_##Name##s;\
public:\
void add_##Name(const Class& a_##Name) {\
m_##Name##s.push_back(a_##Name);\
}\
int get_##Name(int pos) {\
return m_##Name##s.at(pos);\
}\
// ... more member functions
Later you can declare a class like
class my_class {
CONTAINS(int, integer)
// ...
};
and write
my_class a(...);
a.add_integer(10);
I was puzzled about this paste-in-macro-style because I'm missing concrete counter-arguments. But beside that I accept the following pros
you can easily add a list interface for arbitrary types to your class
you avoid frequently repeated code
you have an easy to use interface (like add_integer(10))
Now I'm searching for alternatives which meet all these points above and avoid this old C macro style. My first idea was to create an abstract base class template
template<typename T>
class list_interface {
private:
std::list<T> m_list;
public:
void add_element(const T& x) {
m_list.push_back(x);
}
// ... more member functions
};
and add it to my class via inheritance like this
class my_class : public list_interface<int> {
// ...
};
Now I can write too
my_class a;
a.add_element(10);
but I'm concerned about the following points:
you can only add one list to your class
you publicly inherit from a class without virtual destructor
I don't meet the third point of the pros (add_element(10) instead of add_integer(10))
My questions are:
What are the drawbacks of the old C macro construct
How can I provide a similar functionality without macros
How about:
#include <vector>
template<typename T>
class Plop
{
std::vector<T> data;
public:
void add(T const& v) {data.push_back(v);}
T get(int pos) {return data.at(pos);} // at() is not valid on lists.
};
class my_class
{
public:
Plop<int> integer;
Plop<float> floater;
};
int main()
{
my_class x;
x.integer.add(5); // similar to x.add_integer(5);
x.integer.get(0); // similar to x.get_integer(0);
}
It meets all the requirements:
you can easily add a list interface for arbitrary types to your class
you avoid frequently repeated code
you have an easy to use interface (like add_integer(10))
My questions are:
What are the drawbacks of the old C macro construct
The ick factor.
Debugging.
Can pass individual list to other functions or methods.
How can I provide a similar functionality without macros
See above.
my opinion
1) Yuck yuck. Complex macro which will hinder debugging. Just the view of the macro makes my skin crawl.
2) Your inheritance solution looks fine. If you really needed multiple lists of different types, you might want to consider just writing more code and instantiating the list as a member variable. There really is no benefit of attempting to reduce lines of code by making it convoluted.
There is a way, in meta-programming fashion, and using tags.
First, let's consider the roll your own solution.
The idea is to come up with this interface:
class my_class : public vector<Name, std::string>, public vector<Foo, int>
{
};
And then, to use it like this:
my_class a;
a.add<Name>("Peter");
a.add<Foo>(3);
Now, lets dive behind the covers. We are going to use SFINAE combined with enable_if.
template <class Tag, class Type>
class vector
{
template <class T, Return>
struct Enable
{
typedef typename boost::enable_if<
boost::is_same<T,Tag>,
Return
>::type type;
}; // Enable
public:
template <class T>
typename Enable<T,void>::type
add(Type const& i) { m_elements.push_back(i); }
template <class T>
typename Enable<T, Type const&>::type
get(size_t i) const { return m_elements.at(i); }
// You'd better declare a whole lot of other methods if you really want that
// like empty, size and clear at the very least.
// Just use the same construct for the return type.
protected:
vector() : m_elements() {}
vector(vector const& rhs) : m_elements(rhs.m_elements) {}
vector& operator=(vector const& rhs) { m_elements = rhs.m_elements; return *this; }
~vector() {} // Not virtual, because cannot be invoked publicly :)
private:
std::vector<Type> m_elements; // at() is inefficient on lists
};
How does this work ?
Basically when you invoke get<Name> the compiler has 2 alternatives:
vector<Name,std::string>::get
vector<Foo,int>::get
Now, thanks to enable_if, the second alternative is ill-formed (the type deduced cannot be used because Foo != Name), and thus, thanks to SFINAE, this alternative is removed from the list without any complaint.
Then, since there is only one alternative, it gets selected. And of course, since this is done at compile-time, you don't actually have any runtime penalty.
If you want to skip some work (for this type). You could also simply use a simpler construct:
template <class Tag, class Embedded>
class Embed
{
// redeclares same private and protected interface
public:
template <class T>
typename Enable<T,Embedded &>::type get() { return m_element; }
template <class T>
typename Enable<T,Embedded const&>::type get() const { return m_element; }
private:
Embedded m_element;
};
Then you use it like so:
class my_class: public Embed< Names, std::vector<std::string> >,
public Embed<Foo,int>
{
};
my_class a;
std::vector<std::string> const& names = a.get<Names>();
int foo = a.get<Foo>();
a.get<Names>().push_back("Peter");
It's easier since you only provide accessors and don't have to write a whole bunch of methods just to forward the work.
And now that we've work so much, we should ask ourselves: this seems quite practical and generic, surely there is a library or something ?
There is >> Boost.Fusion's map:
class my_class
{
public:
template <class Tag>
typename result_of::at_key<map_type, T>::type &
get() { return at_key<T>(m_data); }
template <class Tag>
typename result_of::at_key<map_type, T>::type const&
get() const { return at_key<T>(m_data); }
private:
// First element of the pair: TAG
// Second element of the pair: Actual type of the data
typedef boost::fusion::map <
std::pair<Name, std::vector<std::string> >,
std::pair<Foo, int>
> map_type;
map_type m_data;
};
The main issue with the macro is: it is solving a problem you don't really have.
It is making a class with list members, where the lists are manipulated directly.
Because we think in OO, members should be encapsulated and we want to use DRY, we come to this construct, while my_class remains really a data-class.
If all the class has to do is contain lists, turn it into a struct and keep the lists public.
This way you have a clean intention and the lists can be accessed the STL-way.
If the class needs to have control over the lists, then you shouldn't expose the lists and the macro's are of little use.
So my code would be (not compiled):
struct my_class {
std::list<int> integers;
std::list<std::string> names;
// ...
};
int main()
{
my_class lists;
lists.integers.push_back(5);
size_t size_names = lists.names.size();
}
Pro:
easily add lists
no code duplication
consistent (STL) interface
straightforward
no macro's
Con:
no data encapsulation, if that would be a requirement
For multiple lists, you can try multiple inheritance with typedefs. Something like:
class my_class : public list_interface<int>, public list_interface<float> {
public:
typedef list_interface<int> Ints;
typedef list_interface<float> Floats;
//...
};
and use like:
my_class a;
a.Ints::add_element(10);
a.Floats::add_element(10.0f);