Specializing hash class for nested class C++ - 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.

Related

Partial specialization of a nested class

How to partially specialize nested class without partially specializing the nesting class?
Implementation of class C is the same for all N.
Implementation of C::iterator is special for N=1.
template<class T, int N>
class C
{
class iterator;
...
};
template<class T, int N>
class C<T, N>::iterator
{
...
};
// Partial specialization doesn't compile:
template<class T>
class C<T, 1>::iterator
{
...
};
I can partially specialize class C for N=1, but that's a lot of code duplication...
If you do not want to specialize whole class then just move the iterator out of class and make it template:
template<class T, int N>
class C_iterator
{
...
};
If needed make your specializations:
template<class T>
class C_iterator<T, 1>
{
...
};
Then use it in your class as iterator, if needed befriend it:
template<class T, int N>
class C
{
using iterator = C_iterator<T, N>;
friend iterator;
...
};
The reason is that:
template<class T>
class C<T, 1>::iterator {
// ...
}
Attempts to be the definition for a member class iterator on a partial specialisation for C, where no such partial specialisation exists. The exact same issue would happen if you tried this with a non-static data member, a member function, or a member template: C++ does not allow partial specialisations where only the outer class is partially specialised.
For example, this compiles:
template<class T, int N>
class C {
class iterator; // (A)
};
template<class T>
class C<T, 1> {
class iterator; // (B)
};
template<class T, int N>
class C<T, N>::iterator {}; // Definition for entity declared at (A)
template<class T>
class C<T, 1>::iterator {}; // Definition for entity declared at (B) *not a partial template specialisation
Whereas without the partial specialisation near (B), there is nothing for the second definition to define. As a general rule of thumb, a partial specialisation can only refer to the innermost entity, so it must be a template.
(Note this has nothing to do with what kind of entity iterator is: The same issue would have happened if iterator was a template class and you try to partially specialise it based on N=1)
So the simplest answer is: you can't do exactly what you want to do.
The simplest solution is what Öö Tiib's answer is: Lift the class out and make iterator a member type alias.
For fun, you could make iterator a template class so you can partially specialise it. You still can't partially specialise the outer class only, so I use a constraint to emulate it:
template<class T, int N>
class C
{
template<std::nullptr_t = nullptr>
class iterator;
};
template<class T, int N>
template<std::nullptr_t>
class C<T, N>::iterator
{
};
template<class T, int N>
template<std::nullptr_t dummy> requires (N==1)
class C<T, N>::iterator<dummy>
{
};
// The first is a primary definition, the second a partial specialisation
// (Could have also made them both partial specialisations, with the first `requires (N!=1)`)
By re declare the iterator class, You can get the same result.
template<class T, int N>
class C
{
class iterator {};
};
template<class T>
class C<T, 1>
{
class iterator {};
};
It should be separated from the common working part of the class. (unless you want to rewrite it)
template<class T>
class CWork
{
};
template<class T, int N>
class C : public CWork<T>
{
class iterator {};
};
template<class T>
class C<T, 1> : public CWorkDefine
{
class iterator {};
};

Template Class Inside Template Class - Different Parameter

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.

Template dependent typedefs

I am modifying a templated A* search and now have the following class (part of):
template <typename TNode, typename THeuristic>
class AStar
{
public:
// Typedefs.
typedef d_ary_heap<TNode*, boost::heap::compare<NodeCompare<TNode>>, boost::heap::arity<4>, boost::heap::mutable_<true>> PriorityQueueType;
//...
}
Until now, I hadn't thought of templatizing the heuristic parameter, so the Node class was defined as follows:
template <typename T = float>
class Node
{
public:
// Typedefs:
typedef typename AStar<Node>::PriorityQueueType::handle_type HeapHandle;
//...
}
But now since AStar takes a second template paremeter for the heuristic the typedef gives a compile error here: typedef typename AStar<Node ??>.... Is it possible to make this work somehow while maintaining freedom to specify the heuristic in the AStar class?
You could factor your code differently and keep the heuristic-independent part separate:
namespace detail
{
template <typename T>
struct AStarHeap
{
using QueueType = /* ... */;
using HandleType = QueueType::handle_type;
// ...
};
}
template <typename Node, typename Heur>
struct AStar : detail::AStarHeap<Node>
{
// ...
};
template <typename T>
struct Node
{
using HeapHandle = typename detail::AStarHeap<T>::HandleType;
// ...
};
Reworking a bit from my comment on the question, here's how I would probably do it:
template <typename TNode, typename THeuristic = void>
class AStar;
template <typename TNode>
class AStar<TNode>
{
// put everything that does not depend on THeuristic here
};
template <typename TNode, typename THeuristic>
class AStar : public AStar<TNode>
{
// put everything that does depend on THeuristic here
};
Looking at it now, this takes much the same approach as Kerrek SB's answer, but has the advantage that your existing code, which uses AStar<TNode>, continues to compile so long as it does not attempt to do anything that requires THeuristic.

C++: How to return an alias defined in a template class?

So I've got template class (abbreviated) like:
template <typename keyT, typename valueT>
class hashMap {
public:
using dataT = pair<keyT,valueT>;
using maybeT = optional<dataT>;
maybeT notFound = optional<dataT> ();
maybeT find(keyT &v);
<snip>
};
When I try to define find(), I have
template <typename keyT, typename valueT>
hashMap::maybeT hashMap<keyT,valueT>::find(keyT &k)
{
and hashMap::maybeT isn't recognized ("expected a class or namespace"). Qualifying hashMap with keyT and valueT doesn't help, either.
How can I export these aliases (or typedefs, if there is a way to make that work).
You need to disambiguate the dependent name:
template <typename keyT, typename valueT>
typename hashMap<keyT, valueT>::maybeT hashMap<keyT,valueT>::find(keyT &k)
// ^^^^^
{
// ...
}
(Since you're writing a template, you might as well keep everything inline, though, and cut down on the code noise. Otherwise you should add inline to the member function declaration.)

Syntax for specialization of nested template class

I'm trying to figure out the correct syntax for explicit specialization of a nested template class. The following code will better illustrate:
struct Column_Major;
struct Row_Major;
template<size_t rows, size_t cols, typename T, typename Allocator>
class Matrix
{
/* bunch of members */
template <typename storage = Column_Major>
class Iterator
{
/* bunch of members */
};
};
I'd like to write an explicit specialization for template <> class Matrix<...>::Iterator<Row_Major, but the syntax is eluding me. I have a suspicion that it is not possible to explicitly specialize the Iterator class without an explicit specialization of the containing class, Matrix. But I would be very happy if there is a way to do this.
I know I could make the Iterator class a separate class, not a member of the Matrix class, but having the classes nested as such allows me full access to the template parameters and datamebers of the Matrix class, which simplifies things. I know I could work around this if I need to, but I'd first like to investigate and understand the possibilities for the nested approach.
Thanks,
Shmuel
For explicit specialization, you need to specialize the outer class before the inner, you can see this question for example.
There is a workaround that is using partial specialization:
template<size_t rows, size_t cols, typename T, typename Allocator>
class Matrix
{
// Notice the additionnal dummy parameter
// vvvvvvvvvvvvv
template <typename storage = Column_Major, bool = true>
class Iterator
{
};
// Specialization
template <bool dummy>
class Iterator<Row_Major, dummy>
{
};
};
You can make Synxis answer (use of defaulted dummy parameter) even more clean with C++11:
/// template <typename X>, not needed for the example
struct Outer
{
private:
template <typename A, typename D = void>
struct Inner
{
Inner() { cout << "default" << endl; }
};
template <typename D>
struct Inner<int,D>
{
Inner() { cout << "int" << endl; }
};
public:
template <typename T>
using Nested = Inner<T>;
};
The advantage of this improvement is that the signature of Nested has only one template parameter, which I think will help if you want to match it correctly in template meta-programming.
I'm surprised the template parameter for the nested class isn't a parameter of the parent class instead.
The nested class can use the template parameters of the parent and this more closely ties the nested class to the parent. Your use of the word iterator suggests this is good, the iterator surely iterating over the same type the parent contains?
I'd do it like this:
template <class T>
class Outer
{
public:
class Inner
{
void Fn( T in )
{
}
};
};
// specialisation
void Outer<double>::Inner::Fn( double in )
{
}