Template Class Inside Template Class - Different Parameter - c++

Is it possible to create a template class inside a template class like the following
// Container.h
template <typename T>
class Container
{
private:
using iterator = Iterator<Node<T>>;
using const_iterator = Iterator<const Node<T>>;
// Node struct to hold data.
template <typename T>
struct Node
{
T data_;
};
public:
// Templated iterator for const or non-const.
template <typename NodeType>
class Iterator
{
private:
NodeType* node_;
public:
Iterator();
};
};
#include "Container.tpp"
So here I declare a template for an iterator that takes in a NodeType which is different from the T that the container class template takes.
If this is possible to do, how do I implemenet the Iterator() inside a different file? Something like
// Container.tpp
template <typename T>
LinkedList<T>::LinkedListIterator<NodeType>::Iterator()
{
// Implementation ...
}
This does not seem right since I do not have access to the NodeType. Any advice would be appreciated.

You should define it as
template <typename T> // for the enclosing class template
template <typename NodeType> // for the member template
Container<T>::Iterator<NodeType>::Iterator()
{
// Implementation ...
}
BTW: The member class template Node can't use the same template parameter name T as the outer class template.

Related

Make new instance of the template class of a c++ object

So if I have
template <class T>
class Object {
// stuff
};
and I receive an instance of object in a function I want to call the constructor of class T.
void foo(Object object) {
auto newT = object::T();
}
Is this possible?
Typically the best solution is to template the inner type:
template <class T>
void foo(Object<T> object) {
T newT;
}
However, sometimes (with more meta-programming) this sort of solution will be more verbose than the alternatives:
Option 1: store the template variable in the Object class:
template <class T>
class Object {
// stuff
public:
using inner_type = T;
};
Then you can access the template type like so:
template <class Obj>
void foo(Obj object) {
typename Obj::inner_type newT;
}
Option 2: make a type trait (no need to add inner_type to Object):
template <class T>
struct tag {
using type = T;
};
template <class>
struct inner;
template <template <class> class S, class T>
struct inner <S<T>> : tag<T> {};
template <typename T>
using inner_t = typename inner<T>::type;
Which you can then use like so:
template <class Obj>
void foo(Obj object) {
inner_t<Obj> newT;
}
It's probably best to generalise inner_type to take the first inner argument so that it could handle template types with more arguments, like std::vector (second argument has a default):
template <class>
struct front;
template <template <class, class...> class R, class S, class ... Ts>
struct front <R<S, Ts...>> : tag<S> {};
template <typename T>
using front_t = typename front<T>::type;
Demo
No, you create an instance of a class template by specializing the template. You do this by putting the type you want to use in angle brackets:
void foo(Object<int> object) {
// auto newobj = Object<int>(); this will work
Object<int> newobj; // but this has less cruft
}
or
template <class U>
void foo(Object<U> object) {
// auto newobj = Object<U>();
Object<U> newobj {object};
}
Remember that the symbol T does not exist outside the template definition. To get a "real" Object you have to put in an actual type. I chose int but you will probably use something else.
Of course, this will only work if the stuff contains a corresponding constructor:
template <class T>
class Object {
// stuff
public:
Object(); // often implicit but sometimes not
Object(Object<T> const &i) = default;
// more stuff
};

Specializing hash class for nested class C++

The goal is to specialize std::hash to work with a subclass called Node.
And the relevant class is:
template<typename T,
typename Hash = std::hash<T>,
typename Pred = std::equal_to <T>,
typename Alloc = std::allocator<T>>
class disjoint_set
{
public:
typedef Hash hasher;
typedef Pred value_equal;
typedef Alloc allocator_type;
protected:
class Node;
unordered_set<Node> table;
// friend class std::hash; // possible solution
class Node
{
public:
T data;
// .......
};
};
I would like to have a hash function as follows:
size_t operator()(const Node& node) const { return hasher(node.data); }
However, the hasher specialization must be in namespace std. One solution I found was to make the specialization a friend class but in that case I'm unsure how to access the template arguments of the main class?
You can't specialize on a nested class of a class template - you'd have to write something like:
template <class T>
struct hash<typename Outer<T>::Inner> { ... };
But that's a non-deduced context, so can never work.
Instead, just pull your Node out of disjoint_set and make it a standalone class template. At that point, specializing std::hash becomes straightforward and using it inside of disjoint_set is just as easy.

C++ pointer template specialization

I'm trying to design a template class of type T* which is declared as follows:
template <class T>
class StructParamPublic<T*>
{
.....
protected:
T* m_pData;
};
which can be used for creating a struct like this
StructParamPublic <FloatArrayStruct*> m_pFloatArray;
where
FloatArrayStruct
{
float* pData;
size_t arraySize;
};
However, when I compile this I'm getting an error that says StructParamPublic is not a template type.
If I define the following template class
template <class T>
class StructParamPublic
{
.....
protected:
T m_Data;
};
then this error goes away.
For some design consideration I don't want to add the second definition to the framework.
My solution was to come up with something like this
template <class T>
class StructParamPublic
{
.....
protected:
T* m_pData;
};
and it compiled fine.
So my question: Is template <class T> class StructParamPublic some kind of 'base template class' and template <class T>class StructParamPublic<T*>
some sort of derivation of that class?
template <class T> class StructParamPublic<T*>;
is a specialization of
template <class T> class StructParamPublic;
So for your problem, you have several possibilities:
(partial) specialization
template <class T> class StructParamPublic;
template <class T>
class StructParamPublic<T*>
{
// code
protected:
T* m_pData;
};
StructParamPublic<int> would lead to an error of undefined class.
or static_assert
template <class T>
class StructParamPublic
{
static_assert(std::is_pointer<T>::type, "type should be a pointer type");
using value_type = typename std::remove_pointer<T>::type;
// code
protected:
T m_pData; // or value_type* m_pData;
};
StructParamPublic<int> would lead to an clean error thanks to static_assert.
or change meaning of your parameter as your solution.
template <class T>
class StructParamPublic
{
.....
protected:
T* m_pData;
};
StructParamPublic<int> is used here whereas previous solution requires StructParamPublic<int*>.
You don't need to define the second class template. You can just use a forward declaration.
template <class T> class StructParamPublic;
and then you can use
template <class T>
class StructParamPublic<T*>
{
.....
protected:
T* m_pData;
};
You could do it like this:
template<typename T>
class StructParamPublic;
// ^ This just "forward declares" the class for all possible template values
template<typename U>
class StructParamPublic<U*> {
...
};
// ^ This is a partial specialization of the above class template. It will deduce the type of T from the pointer type that you instantiate the template with
If you do it that way then the syntax StructParamPublic<int*> will be legal and it will deduce the type T as int in the template when you use it.
In general when you have template<typename T> class < T::dependent_type > { ... }; you should use a template specialization for it to work the way you expect, and that requires that you make the "primary" template first which is not specialized, even if that primary template doesn't actually do anything (besides make a declaration).
Note also that you don't actually need to use type traits here to enforce the pointer type requirement. In the above code if you try to use it with a non-pointer type, it will just find the primary template only and not find a real definition. If you wanted you could add a static assert in the primary template "missing * in StructParamPublic<...>" or similar.

How to define a function for a (somewhat) partially specialized class

I'm not sure if what I'm trying to do is possible. Here's an example:
template <typename T>
class Ref
{
void Decrement();
};
template <typename T>
class Collection {};
// This will error
template <>
template <typename T>
void Ref<Collection<T>>::Decrement() {}
You can't specialize just one function inside a class template; you have to specialize the class template as a whole.
template <typename T>
class Ref
{
void Decrement();
};
template <typename T>
class Collection {};
template <typename T>
class Ref<Collection<T>> {
void Decrement() {}
};
You can specialize a function template inside a class, i.e., this:
class Ref {
template <typename U> void Decrement();
};
or a function template inside a class template...
template <typename T>
class Ref {
template <typename U> void Decrement();
};
However, even then, a partial specialization, which is what you want to do, cannot be done for a function template; function templates can only be fully specialized for individual types, and never partially specialized, whereas class templates can be either partially or fully specialized.

Template specialization by another template (of same class)

I'm writing an array class. This array class can contain again arrays as members. When implementing a printing function, I need specializations.
26:template <class T> class array : public vector<T>{
public:
...
string* printToString();
...
};
...
template <class T> string* array<T>::printToString(){
... // generic function
}
template <> inline string* array<double>::printToString(){
... // spezialization for double, works
}
561:template <class U> string* array<array<U>*>::printToString(){
... // does not work
}
The last definition produces
src/core/array.h:561: error: invalid use of incomplete type ‘class array<array<T> >’
src/core/array.h:26: error: declaration of ‘class array<array<T> >’
The g++ version is g++ (Ubuntu 4.4.3-4ubuntu5) 4.4.3 if that matters.
Any ideas what's the problem?
Thanks in advance,
Thomas
As an alternative to David's solution, you can unconditionally forward the call to a set of overloaded functions:
template <class T> class array;
namespace details {
template <class T> std::string array_print(array<T> const&);
std::string array_print(array<double> const&); // Regular function
template <class T> std::string array_print(array<array<T> > const&);
}
template <class T> class array : private vector<T> {
public:
...
std::string printToString() { return details::array_print(*this); }
...
};
namespace details { /* implementions after class is defined */ }
You cannot partially specialize a function, you can only fully specialize it, which is the reason why you can provide an specialization for double but not for array<U> where U is a generic type.
You can get around this limitation by using a class template, and partially specializing that, but it will be a bit cumbersome.
namespace detail {
template <typename T>
struct array_printer {
static std::string print( array<T> const & array ) {
// basic implementation
}
};
template <typename T>
struct array_printer< array<T> > {
static std::string print( array< array<T> > const & array ) {
// specialization for array<T>
}
}
}
And then implement the member function as a simple dispatch to the appropriate overload:
template <typename T>
class array : std::vector<T> { // do not publicly derive from STL containers
public:
std::string printToString() const {
return detail::array_printer<T>::print( *this );
}
}
Of course, things are a little more complex in real code, and you will have to order the code appropriatedly, and provide forward declarations of the templates and all that, but this should be enough to get you started.
Your function must be fully specialized. For example:
// Fully specialized. You cannot replace `double` with generic parameter.
template <>
string* array<array<double>*>::printToString(){
return nullptr;
}
However, your class can be partially specialized. For example:
template <class T> class array : public vector<T>{
public:
string* printToString();
};
template <class T> string* array<T>::printToString(){
return nullptr;
};
// Partial specialization.
template <class T> class array<array<T>*> : public vector<T>{
public:
string* printToString();
};
template <class T> string* array<array<T>*>::printToString(){
return nullptr;
};
-- EDIT ---
The methods from generic class will not be automatically "taken" by the class specialization, or vice-versa. You can, however use inheritance to "automate" the reuse of methods from generic class. For example...
template <class T> class array : public vector<T>{
public:
string* printToString();
void f();
};
// (1a)
template <class T> string* array<T>::printToString(){
return nullptr;
};
// (2)
template <class T> void array<T>::f(){
};
template <class T> class array<array<T>*> : public array<T> {
public:
string* printToString();
};
// (1b)
template <class T> string* array<array<T>*>::printToString(){
return nullptr;
};
void Test() {
array<double> a1;
a1.printToString(); // Calls (1a).
a1.f(); // Calls (2).
array<array<char>*> a2;
a2.printToString(); // Calls (1b).
a2.f(); // Calls (2).
}
...which may or may not be what you need (some "manual" repetition might be necessary).