I have a templated node class declared as
template <class T_>
class Node : public std::iterator<std::bidirectional_iterator_tag, T_, T_>
{
...
}
Which works fine, and I'm trying to take this existing class and apply it to a new linked list class.
I'd like to create it by calling something along the lines of
LinkedList<float> nodeList;
where it implicitly takes the type given, and within the structure of the class handles it as Node of type T_.
Is there a way to do this without making the node a sub-class of LinkedList?
Is this what you are asking?
template <class T_>
class LinkedList
{
public:
typedef Node<T_> node_type;
void AddNode(node_type *node)
{ /*...*/ }
};
Technically, the typedef is not necessary, but IME it is a good pratice to typedef the dependent types in this way.
You can provide the iterator as a default template argument:
template<
class T,
class Iterator = Node<T>
> class LinkedList
{
// ...
};
If i understood your question correct, you need to instantiate a class template using templated class type. Use this syntax:
LinkedList<Node<float> > nodeList;
(notice a space between > >; it is always a good idea to add it, because old versions of some compilers have troubles on distinguishing such constructs from shift operators >>)
Related
I am trying to use templates for a nested class. I am not sure how to access the class type of the inner class from another class.
Sample Code below.
// I have a List class that can accept any type. It has an inner class
template <class T>
class List
{
public:
class Node
{
public:
T data;
Node* next;
Node* prev;
};
void addElement(Node& value);
private:
Node* head;
};
// Here I am making an array of Lists
template <class T>
class ListArray
{
public:
// Here is my question.
void add(Node& value); // How to give "Node" class type here ?
private:
List<T> _listArr[10];
};
// Is the below the right way to define ListArray::add, especially the way in which Node type can be passed to it ?
template <class T>
void ListArray<T>::add(List<T>::Node& value)
{
// Make a call to List::addElement and pass Node& value
_listArr[0].addElement(value);
//....
}
Could you kindly let me know how the above can be achieved ? Thanks.
Node is a nested type of a class template:
template <class T>
class ListArray
{
public:
typedef typename List<T>::Node Node_type;
void add(Node_type& value); // Refer to it as Node_type
private:
List<T> _listArr[10];
};
And:
template <class T>
void ListArray<T>::add(typename ListArray<T>::Node_type& value)
{
_listArr[0].addElement(value);
//....
}
I used typedef to define local name for node type. It is very useful - now, clients of ListArray can write code, that uses Node_type explicitly (without knowing what it actually is). This technique is used heavily in std library - usually, std:: types have tons of typedefs to allow writing flexible code.
Also, note the typename keyword - it is required in case of nested types of class templates. It indicates, that given name is the name of a type (without it, you should get a compiler error).
Why do templates let you get around incomplete types?
I was following an example in a textbook on Nodes, Linked lists and Iterators. I noticed he used a pointer to instances of Lists and Nodes in the Iterator class, but then he also created a method in the List class to return an Iterator for that class. When I tried to implement it myself to save time I didn't template it and chose int data instead, however I would get an error of incomplete type for my Iterator-typed method. When I followed the template notation it worked fine.
template<class Datatype> class Object;
template<class Datatype> class List;
template<class Datatype> class Helper;
template <class Datatype>
class Object {
public:
Object() : m_data(), next(0) {}
Datatype m_data;
Object<Datatype>* next;
};
template <class Datatype>
class List{
public:
List() : m_head(0), m_tail(0) {}
Object<Datatype>* m_head;
Object<Datatype>* m_tail;
int m_count;
Helper<Datatype> getHelper()
{
return Helper<Datatype>( m_head, this);
}
};
template <class Datatype>
class Helper {
public:
Helper( Object<Datatype>* p_node, List<Datatype>* p_list);
Object<Datatype>* m_node;
List<Datatype>* m_list;
};
edit: There may have been some confusion to what my question was referring to. It was referring to the class-typed method
Helper<Datatype> getHelper()
When hard-typed it results in an error of incomplete type. I was wondering how templates got around this? I have some idea that its because a template allows types of different memory sizes then it doesn't handle that methods memory return size until compile-time. I'm quite curious as to how this works, if anyone has an answer I'd appreciate it.
Lines 1-3 in the code that you've posted forward-declare all your classes, so pointers to instances of these can now be resolved by the compiler, before it has seen the full definition.
The same technique works in the non-template case.
Edit after updated OP:
In non-template classes, to use an actual object (as opposed to just a pointer) you need to have the full class definition available. So the forward declarations are not enough and it will give you an error when you try to return an instance of Helper.
Templates are not instantiated until you use them, which in your case is after you have provided a full definition of Helper, so the compiler has no problem finding it.
How do I declare a templated type that refers to itself?
template <class T = Animal> class Animal
{
public:
T getChild ();
}
With this, I get a compiler error concerning a missing type specifier. I tried to forward-declare Animal, without success.
I am trying to impose a type constraint. A Lion can only have a Lion as a child, a Bear has a Bear, and so on.
EDIT
I'll post part of the actual class. It is a template for classes that can appear in a linked list:
template <class T = Linked<T> > class Linked
{
private:
T* m_prev;
T* m_next;
}
I want to enforce that the class can only point to object of the same class (or a subclass).
In this case, you need to specify some type parameter to Animal in your typename definition, or else it would be an "infinite recursion" in the type construction:
template<class T> class Animal;//you'll need this forward declaration
template <class T = Animal<int> > class Animal //int is just an example
{
public:
T getPrey ();
}
The OP has been answered but I want to chime in because the immediate cause of the problem is not recursion, as others claim. The simplest reason this wouldn't work is that class templates are not types. They are templates. Similarly, function templates are not functions either. So all of this is nonsensical:
template<typename T> int function_template(int);
typedef int function_type(int);
void eats_a_function(function_type&); // needs a reference to function
std::vector< std::vector > vec0; // std::vector is not a type
std::vector< std::list > vec1; // std::list is not a type
eats_a_function(function_template); // function_template is not a function
Notice that in the vec1 case, std::list is not related to std::vector. The template is fully defined (assuming header inclusion) at the point of instantiation. It still won't work.
Instead, the following works:
std::vector< std::vector<int> > vec2; // std::vector<int> is a type
std::vector< std::list<double> > vec3; // std::list<double> is a type
eats_a_function(function_template<long>); // function_template<long> is a function
Notice that in the vec2 case, it's fine to pass an instantiation of the template itself.
For the record, a toy solution to the toy problem on writing a template that refers to itself, using the proverbial layer of indirection:
// expects a template that expects a type
template<template<class> class T> struct indirection {};
// forward decl. for defaulting the parameter
template<typename T> struct recursive;
// template that expects a type
template<typename T = indirection<recursive> > struct recursive {};
Not terribly powerful given the few things that are possible with a template (the T parameter inside indirection). It's of course possible to write a rebind-style metafunction that returns an instantiation of T.
The usual way to do something like a linked list is:
template <class T> class Linked
{
private:
Linked<T>* m_prev;
Linked<T>* m_next;
}
Does this work for you, and if not, what are you trying to accomplish that can't be done this way?
You can't create a template class wherein the template type is the class itself. This is a logical recursion that your compiler can't mitigate. Since templates require the compiler to construct the object when a specific typing is encountered ( say Animal ), you have to have a complete definition of the template type. Otherwise, the compiler will recursively try to construct objects. Since your object self-references, this will be an non-terminating recursion.
This use-case seems much more appropriate for inheritance than for templates.
Doing this will let you compile:
template class Animal
{
public:
T getPrey ();
}
Or, if you really wan't a default argument:
template <class T=Cheetah> class Animal
{
public:
T getPrey ();
}
Yet, cheetah must not use itself or Animal as one of its potential template types.
I'm trying to create a list of objects, where each object also stores 'ownership' - ie, it knows which list holds it.
In a non-template situation, it's straightforward:
class FooList; // forward declaration
class FooItem
{
public:
FooList *owner;
...
};
class FooList: private std::list<FooItem>
{
...
};
However, the list class is a template, based on the contained object type, and I'm struggling to work out how to specify this. I reckon the FooItem class now needs to be a template because the type of 'owner' can vary:
template <class E> class FooItem
{
public:
std::list<E> *owner;
};
template <class E> class FooList: private std::list<E>
{
...
};
But, now given my two templates, how can I define the new types I want? The snippet below is what I think I need, but it gives "error: Multiple declaration for BarItem".
class BarItem;
typedef FooList<BarItem> BarList;
typedef FooItem<BarList> BarItem;
EDIT:
Thanks to those who pointed out the issue of std::list<E> instead of std::list<FooItem<E> >
EDIT 2:
Renamed classes to Base, Derived, BaseList, DerivedList.
My real problem was the 'circular typedef'. After some more tinkering, I think this will do what I require. It creates a 'real' BarItem class rather than just a typedef, but seems to at least compile now.
template <class E> class BaseList; // forward declaration
template <class E> class Base
{
public:
BaseList< Base<E> > *owner;
};
template <class E> class BaseList: private std::list< E >
{
};
// typedef Base<BaseList<Derived> > Derived; //This won't compile, unsurprisingly.
class Derived : public Base < BaseList<Derived> > // Surprisingly, this seems to.
{
...
};
typedef BaseList<Derived> DerivedList;
Does this seem to make sense? Is it a common idiom or something horrible?
Are you sure you didn't want:
template <class E> class FooItem
{
public:
std::list< FooItem<E> > *owner; // owned by a list of FooItem<E>, not raw E
};
template <class E> class FooList: private std::list< FooItem<E> > // is a list of FooItem<E>, not raw E
{
...
};
The error you are getting is because you forward declare the class BarItem but later try to redefine that name using typedef. Not sure what you're trying to accomplish, but you'll need to introduce a third name. Maybe you meant:
class Bar;
typedef FooItem<Bar> BarItem;
typedef FooList<Bar> BarList;
EDIT: The new code you've posted certainly compiles, but seems very awkward (for one thing, the naming seems really confusing). Perhaps you should ask a new question with a more concrete example of why you think you need an 'item which is an item of lists of itself' and see if others can come up with a less awkward design.
Is that last set of typedef statements correct? You posted this:
class BarItem;
typedef FooList<BarItem> BarList;
typedef FooItem<BarList> BarItem;
It's somewhat recursive, right? The first statement says there's a class BarItem that exists elsewhere. The second statement says that the type FooList<BarItem> (a list of BarItem objects) can also be referred to as BarList. The third statement says that the type FooItem<BarList> can also be referred to as BarItem, but BarItem was already defined as a type by the class BarItem statement.
So you're saying that BarItem is a type all to itself (via the class statement), but you're also saying that BarItem is an alias for the type FooItem<BarList>. Hence the conflict.
If you just want to generalize your first approach to a templated FooItem class, it would look like this:
template <class E> class FooList; // forward declaration
template <class E> class FooItem
{
public:
FooList<E> *owner;
...
};
template <class E> class FooList: private std::list< FooItem<E> >
{
...
};
If that is not what you want I'm not sure what exactly you are attempting to do.
I have my templated container class that looks like this:
template<
class KeyType,
class ValueType,
class KeyCompareFunctor = AnObnoxiouslyLongSequenceOfCharacters<KeyType>,
class ValueCompareFunctor = AnObnoxiouslyLongSequenceOfCharacters<ValueType>
>
class MyClass
{
[...]
}
Which means that when I instantiate an object of this class, I can do it several different ways:
MyClass<MyKeyType, MyValueType> myObject;
MyClass<MyKeyType, MyValueType, MyCustomKeyCompareFunctor> myObject;
MyClass<MyKeyType, MyValueType, MyCustomKeyCompareFunctor, MyCustomValueCompareFunctor> myObject;
Those are all good. The problem comes when I want to instantiate a MyClass that uses a non-default version of the ValueCompareFunctor argument, but I still want to use the default value of the KeyCompareFunctor argument. Then I have to write this:
MyClass<MyKeyType, MyValueType, AnObnoxiouslyLongSequenceOfCharacters<MyKeyType>, MyCustomValueCompareFunctor> myObject;
It would be much more convenient if I could somehow omit the third argument and just write this:
MyClass<KeyType, ValueType, MyCustomValueCompareFunctor> myObject;
Since the MyCustomValueCompareFunctor works only on objects of type MyValueType and not on objects of type MyKeyType, it seems like the compiler could at least theoretically work out what I meant here.
Is there a way to do this in C++?
In general, both in templates and functions or methods, C++ lets you use default for (and thereby omit) only trailing parameters -- no way out.
I recommend a template or macro to shorten AnObnoxiouslyLongSequenceOfCharacters<MyKeyType> to Foo<MyKeyType> -- not perfect, but better than nothing.
No. The closest you can come is to allow users to specify some sentinel type - like void - meaning "use default value here", and use template metamagic inside your class to typedef the real default if void was given to you. But this probably isn't a good idea from readability point of view.
Boost parameters and Boost graph named parameters are efforts towards naming parameters for template functions/methods. They give the opportunity to provide arguments in whichever order you prefer. Some arguments may be optional, with default values.
The same approach may be applied to template arguments. Instead of having N template arguments + P optional ones, create your class with N+1 template arguments. The last one will hold "named" parameters which can be omitted.
This answer is not complete yet, but i hope it's a good start !
An alternative option is to use Traits classes:
template <class KeyType>
class KeyTraits
{
typedef AnObnoxiouslyLongSequenceOfCharacters<KeyType> Compare;
};
template <class ValueType>
class ValueTraits
{
typedef AnObnoxiouslyLongSequenceOfCharacters<ValueType> Compare;
};
template<class KeyType class ValueType>
class MyClass
{
typedef KeyTraits<KeyType>::Compare KeyCompareFunctor;
typedef ValueTraits<ValueType>::Compare KeyCompareFunctor;
};
Then if you have a type which needs a different comparison function for Key's, then you'd explicitly specialize the KeyTraits type for that case. Here's an example where we change it for int:
template <>
class KeyTraits<int>
{
typedef SpecialCompareForInt Cmopare;
};
There is another option, which uses inheritance and which works like the following. For the last two arguments, it uses a class that inherits virtually from a class that has two member templates, that can be used to generate the needed types. Because the inheritance is virtual, the typedefs it declares are shared among the inheritance as seen below.
template<class KeyType,
class ValueType,
class Pol1 = DefaultArgument,
class Pol2 = DefaultArgument>
class MyClass {
typedef use_policies<Pol1, Pol2> policies;
typedef KeyType key_type;
typedef ValueType value_type;
typedef typename policies::
template apply_key_compare<KeyType>::type
key_compare;
typedef typename policies::
template apply_value_compare<ValueType>::type
value_compare;
};
Now, have a default argument that you use, which has typedefs for the default arguments you want provide. The member templates will be parameterized by the key and value types
struct VirtualRoot {
template<typename KeyType>
struct apply_key_compare {
typedef AnObnoxiouslyLongSequenceOfCharacters<KeyType>
type;
};
template<typename ValueType>
struct apply_value_compare {
typedef AnObnoxiouslyLongSequenceOfCharacters<ValueType>
type;
};
};
struct DefaultArgument : virtual VirtualRoot { };
template<typename T> struct KeyCompareIs : virtual VirtualRoot {
template<typename KeyType>
struct apply_key_compare {
typedef T type;
};
};
template<typename T> struct ValueCompareIs : virtual VirtualRoot {
template<typename ValueType>
struct apply_value_compare {
typedef T type;
};
};
Now, use_policies will derive from all the template arguments. Where a derived class of VirtualRoot hides a member from the base, that member of the derived class is dominant over the member of the base, and will be used, even though the base-class member can be reached by other path in the inheritance tree.
Note that you don't pay for the virtual inheritance, because you never create an object of type use_policies. You only use virtual inheritance to make use of the dominance rule.
template<typename B, int>
struct Inherit : B { };
template<class Pol1, class Pol2>
struct use_policies : Inherit<Pol1, 1>, Inherit<Pol2, 2>
{ };
Because we potentially derive from the same class more than once, we use a class template Inherit: Inheriting the same class directly twice is forbidden. But inheriting it indirectly is allowed. You can now use this all like the following:
MyClass<int, float> m;
MyClass<float, double, ValueCompareIs< less<double> > > m;