I'm creating a container class which implements a double linked list.
template <class T>
class dl_list {
public:
class link {
public:
T* data;
link *prev, *next;
};
class iterator {
link* node;
public:
link* get_node() { return node; }
// ++, --, * operators, etc.
};
// other stuff
};
Pretty neat, I'm having fun with it. But one problem I'm having is when I define my equality operators for the iterator type, I have to do a template specialization.
template <class T>
bool operator==(typename dl_list<T>::iterator& lhv, typename dl_list<T>::iterator rhv) {
return lhv.get_node() == rhv.get_node();
}
will not work, I have to specialize it like so:
bool operator==(typename dl_list<int>::iterator& lhv, typename dl_list<int>::iterator rhv) {
return lhv.get_node() == rhv.get_node();
}
for every type I want to use it for, which is annoying for obvious reasons. How do I get around this?
Make it a member of the iterator class:
bool operator==( const interator& other ) const
{
return node == other.node;
}
You can't. The compiler cannot know that some T is a nested type of some other U. Consider
template<> class dl_list<float> {
public:
typedef dl_list<int>::iterator iterator;
};
You have to take the iterator type directly as the template parameter, or define it as a member of the iterator class, or define the iterator class outside dl_list and simply make a typedef for it inside dl_list.
Easiest cleanest way is to define the operator inside the iterator class:
class iterator
{
public:
...
friend bool operator==(iterator& lhs, iterator& rhs)
{
return lhs.get_node() == rhs.get_node();
}
};
(Bit of a code smell here - I'd have expected get_node() to have a const version, allowing the operator== to accept parameters by const reference...)
Related
#include <iostream>
template <typename T>
struct Node
{
T value;
Node<T>* next;
};
template <typename T>
struct LinkedList
{
// head, tail....
// some implementation...
};
template<
template<typename> typename node,
typename T,
template<typename> typename iterator,
template<typename> typename const_iterator
>
struct SomeComonFunctionsBetweenIterators
{
node<T>* ptr;
// some implementation...
SomeComonFunctionsBetweenIterators(node<T>* ptr) : ptr(ptr) {}
T& operator*() { return ptr->value; }
iterator<T> GetIterator() { return iterator<T>(ptr); }
// doesn't work. want some way like this instead of passing the
// const iterator as a template argument.
//operator const_iterator<T>() { return iterator<const T>(ptr) ; }
operator const_iterator<T>() { return const_iterator<T>(ptr); }
};
template <typename T>
struct LinkedListConstIterator;
template <typename T>
struct LinkedListIterator
: public SomeComonFunctionsBetweenIterators<Node, T, LinkedListIterator, LinkedListConstIterator>
{
LinkedListIterator(Node<T>* ptr)
: SomeComonFunctionsBetweenIterators<Node, T, LinkedListIterator, LinkedListConstIterator>(ptr) {}
// some implementation...
};
template <typename T>
struct LinkedListConstIterator : public LinkedListIterator<T>
{
LinkedListConstIterator(Node<T>* ptr) : LinkedListIterator<T>(ptr) {}
const T& operator*() { return static_cast<const T&>(this->ptr->value); }
};
int main()
{
Node<int> node{ 5, nullptr };
LinkedListIterator<int> it(&node);
std::cout << *it << '\n';
LinkedListConstIterator<int> cit = it;
std::cout << *cit << '\n';
}
In this code I have a linked list and an iterator to it. Also I have a const iterator which inherits from the normal iterator and when dereferenced, returns a const T. The iterator can be for a singly linked list or a doubly linked list and most of the functions in both of them are the same (dereferencing or comparing for example). So I extracted the common functions and put it in a common struct. I want to be able to asign normal iterators to const iterators. So I pass the const iterator to the normal iterator as a template argument and define a conversion operator from the normal iterator to const iterator. This way works but it requires me to always pass the const iterator alongside the normal iterator as a template argument.
Is there any better way to implement const_iterators? instead of passing the const iterator everywhere. How the const_iterators are implemented for example in the STL containers?
How the const_iterators are implemented for example in the STL containers?
You can probably look in your implementation's header files to see how they chose to do it. It will depend on the container type and its internal data structure. But the common pattern I've seen is that there's some private template that can take either non-const T or const T, and that will be used as a base or member of the actual distinct iterator types. One catch is that a specific type from the data structure needs to be used, independently of the type the iterator classes expose. In your example, Node<T> and Node<const T> are not interoperable, so SomeComonFunctionsBetweenIterators could work, but should probably have the node type as a template argument independent of the value type T.
But for an easy way to define iterator types, I always turn to Boost.Iterator's iterator_facade or iterator_adaptor. They take care of a lot of the technical requirements about iterators, letting the author just fill in the behavioral bits. iterator_facade is for implementing something "from scratch", and iterator_adaptor is for the common case of an iterator that contains and wraps another iterator.
The Boost documentation for iterator_facade discusses a way to define related iterator and const_iterator types. (Though their decision to make the iterators interoperable as long as the pointers can convert probably wouldn't be appropriate for iterators from containers.)
Using iterator_facade will also give a bunch of things algorithms may expect of iterators but missing from your code shown, like making std::iterator_traits work, equality and inequality, and other fiddly details.
#include <boost/iterator/iterator_facade.hpp>
#include <type_traits>
template <typename T>
struct Node
{
T value;
Node* next;
};
template <typename NodeType, typename ValueType, typename ContainerType>
class TLinkedListIterator :
public boost::iterator_facade<
TLinkedListIterator<NodeType, ValueType, ContainerType>, // CRTP Derived type
ValueType, // Iterator's value_type
std::forward_iterator_tag // Category
>
{
public:
TLinkedListIterator() : m_node(nullptr) {}
protected:
explicit TLinkedListIterator(NodeType* node) : m_node(node) {}
private:
friend boost::iterator_core_access;
friend ContainerType;
template <typename N, typename V, typename C> friend class TLinkedListIterator;
ValueType& dereference() const { return m_node->value; }
void increment() { m_node = m_node->next; }
// Templating allows comparison between iterator and const_iterator
// in any combination.
template <typename OtherValueType>
bool equal(const TLinkedListIterator<NodeType, OtherValueType, ContainerType>& iter)
{ return m_node == iter.m_node; }
NodeType m_node;
};
template <typename T>
class LinkedList
{
public:
using iterator = TLinkedListIterator<Node<T>, T, LinkedList>;
class const_iterator
: public TLinkedListIterator<Node<T>, const T, LinkedList>
{
private:
using BaseType = TLinkedListIterator<Node<T>, const T, LinkedList>;
public:
const_iterator() = default;
// Converting constructor for implicit conversion from iterator
// to const_iterator:
const_iterator(const iterator& iter)
: BaseType(iter.m_node) {}
protected:
explicit const_iterator(Node<T>* node)
: BaseType(node) {}
friend LinkedList<T>;
};
iterator begin() { return iterator(get_head()); }
iterator end() { return iterator(); }
const_iterator begin() const { return const_iterator(get_head()); }
const_iterator end() const { return const_iterator(); }
const_iterator cbegin() const { return begin(); }
const_iterator cend() const { return end(); }
// ...
};
I have the following classes and I am trying to overload the operator* from the inner class iterator
#ifndef __LISTMAP_H__
#define __LISTMAP_H__
#include "xless.h"
#include "xpair.h"
template <typename Key, typename Value, class Less=xless<Key>>
class listmap {
public:
using key_type = Key;
using mapped_type = Value;
using value_type = xpair<const key_type, mapped_type>;
private:
Less less;
struct node;
struct link {
node* next{};
node* prev{};
link (node* next, node* prev): next(next), prev(prev){}
};
struct node: link {
value_type value{};
node (node* next, node* prev, const value_type&);
};
node* anchor() { return static_cast<node*> (&anchor_); }
link anchor_ {anchor(), anchor()};
public:
class iterator;
listmap(){};
listmap (const listmap&) = default;
listmap& operator= (const listmap&) = default;
~listmap();
iterator insert (const value_type&);
iterator find (const key_type&);
iterator erase (iterator position);
iterator begin() { return anchor()->next; }
iterator end() { return anchor(); }
bool empty() const { return begin() == end(); }
};
template <typename Key, typename Value, class Less>
class listmap<Key,Value,Less>::iterator {
private:
friend class listmap<Key,Value>;
listmap<Key,Value,Less>::node* where {nullptr};
iterator (node* where): where(where){};
public:
iterator(){}
value_type& operator*();
value_type* operator->();
iterator& operator++(); //++itor
iterator& operator--(); //--itor
void erase();
bool operator== (const iterator&) const;
bool operator!= (const iterator&) const;
};
template <typename Key, typename Value, class Less>
value_type& listmap<Key,Value,Less>::iterator<Key,Value,Less>::operator*()
{
return where->value;
}
#include "listmap.tcc"
#endif
The problem is that value_type is a public member from the class listmap and it's not static, so I don't know how to complete the declaration of operator*(). I wouldn't like to fix the bug by changing the structure of the code. Ex: making
using value_type = xpair<const key_type, mapped_type>;
Global. I am just wondering if there is some other trick I can use to access value_type.
....edit: I have no idea how the inner class recognizes value_type
It's barely the same as for iterator, you just have to add typename keyword
typename listmap<Key,Value,Less>::value_type
staticness doesn't matter for a type.
The alias1 inside iterator
template <typename Key, typename Value, class Less>
class listmap<Key,Value,Less>::iterator {
...
using value_type = typename listmap<Key,Value,Less>::value_type;
};
allows you to write the definition more succinctly using auto suffix type:
template <typename Key, typename Value, class Less>
auto listmap<Key,Value,Less>::iterator::operator*() -> value_type&
{
return where->value;
}
Careful: inner iterator class is not template, only listmap is:
listmap<Key,Value,Less>::iterator<Key,Value,Less>::operator
// ~~~~~~~~~~~~~~~~ remove this
1 Btw don't forget the others.
To narrow it down: I'm currently using Boost.Unordered. I see two possible solutions:
Define my own Equality Predicates and Hash Functions and to utilize templates (maybe is_pointer) to distinct between pointers and instances;
Simply to extend boost::hash by providing hash_value(Type* const& x) as for hashing; and add == operator overload as free function with (Type* const& x, Type* const& y) parameters as for equality checking.
I'm not sure whether both variations are actually possible, since I didn't test them. I would like to find out you handle this problem. Implementations are welcome :)
EDIT 1:
What about this?
template<class T>
struct Equals: std::binary_function<T, T, bool> {
bool operator()(T const& left, T const& right) const {
return left == right;
}
};
template<class T>
struct Equals<T*> : std::binary_function<T*, T*, bool> {
bool operator()(T* const& left, T* const& right) const {
return *left == *right;
}
};
EDIT 2:
I've just defined:
friend std::size_t hash_value(Base const& base) {
boost::hash<std::string> hash;
return hash(base.string_);
}
friend std::size_t hash_value(Base* const& base) {
return hash_value(*base);
}
And then:
Derived d1("x");
Derived d2("x");
unordered_set<Base*> set;
set.insert(&d1);
assert(set.find(&d2) == end());
Debugger says that friend std::size_t hash_value(Base* const& base) is never called (GCC 4.7). Why is that?
EDIT 3:
I found out that template <class T> std::size_t hash_value(T* const& v) in boost/functional/hash.hpp on line #215 (Boost 1.49) is Boost's specialization for pointers and it simply masks your custom implementation of hash_value such as mine in EDIT 2.
Therefore, it seems like the only way here is to create a custom Hash Functor.
For the hash function, you have a choice between specializing boost::hash (or std::hash in the newer standard) or defining a new functor class. These alternatives work equally well.
For the equality operator, you need to define a new functor, because you cannot redefine the equality operator over pointers. It's a built-in operator (defined in functional terms as bool operator==( T const *x, T const *y )) and cannot be replaced.
Both of these can be defined generically by using a templated operator() in a non-templated class.
struct indirect_equal {
template< typename X, typename Y >
bool operator() ( X const &lhs, Y const &rhs )
{ return * lhs == * rhs; }
};
Follow a similar pattern for the hasher.
Taking into consideration all edits in the original post I would like to provide complete solution which satisfies my needs:
1. Equality:
template<class T>
struct Equal: ::std::binary_function<T, T, bool> {
bool operator()(T const& left, T const& right) const {
::std::equal_to<T> equal;
return equal(left, right);
}
};
template<class T>
struct Equal<T*> : ::std::binary_function<T*, T*, bool> {
bool operator()(T* const & left, T* const & right) const {
Equal<T> equal;
return equal(*left, *right);
}
};
2. Hashing:
template<class T>
struct Hash: ::std::unary_function<T, ::std::size_t> {
::std::size_t operator()(T const & value) const {
::boost::hash<T> hash;
return hash(value);
}
};
template<class T>
struct Hash<T*> : ::std::unary_function<T*, ::std::size_t> {
::std::size_t operator()(T* const & value) const {
Hash<T> hash;
return hash(*value);
}
};
So now I can continue using Boost's hash_value and it will not get masked for pointer types by Boost's default implementation (see EDIT 3).
3. Example:
In my application I have a thin wrapper for unordered_set which now looks like that:
template<class T, class H = Hash<T>, class E = Equal<T> >
class Set {
public:
// code omitted...
bool contains(const T& element) const {
return s_.find(element) != end();
}
bool insert(const T& element) {
return s_.insert(element).second;
}
// code omitted...
private:
::boost::unordered::unordered_set<T, H, E> s_;
};
So if we have some base class:
class Base {
public:
Base(const ::std::string& string) {
if (string.empty())
throw ::std::invalid_argument("String is empty.");
string_ = string;
}
virtual ~Base() {
}
friend bool operator==(const Base& right, const Base& left) {
return typeid(right) == typeid(left) && right.string_ == left.string_;
}
friend bool operator!=(const Base& right, const Base& left) {
return !(right == left);
}
friend ::std::size_t hash_value(Base const& base) {
::boost::hash<std::string> hash;
return hash(base.string_);
}
friend ::std::size_t hash_value(Base* const& base) {
return hash_value(*base);
}
private:
::std::string string_;
};
And some derived class:
class Derived: public Base {
public:
Derived(const ::std::string& string) :
Base(string) {
}
virtual ~Derived() {
}
};
Then we can even use polymorphism (which was my primary intention BTW):
Derived d1("¯\_(ツ)_/¯");
Derived d2("¯\_(ツ)_/¯");
Set<Base*> set;
set.insert(&d1);
assert(set.contains(&d2));
Hope this helps. Any suggestions are welcome.
I'm having troubles in overloading comparison operators in order to compare two pair struct in such way:
typedef pair<string, unsigned int> INDEX;
bool operator>(INDEX &v1, INDEX &v2)
{
if(v1.second == v2.second) //if integer parts are equal
{
//string that comes earlier in the dictionary should be larger
return v1.first < v2.first;
}
return v1.second > v2.second;
}
The actual comparison takes place at this->element(hole/2) < this->element(hole) inside fixUp(CBTNODE hole), a member function of BinaryHeap class, which is a derived class of CompleteBinaryTree. The T will be instantiated as type INDEX, which is typedefed as pair<string, unsigned int>.
In other words, the comparison between two pairs: ("a.txt", 42) > ("b.txt", 42) should return true.
I tried to overload operator> outside the class declaration in two different ways but neither of them worked:
bool operator>(INDEX &v1, INDEX &v2);
bool operator>(BinaryHeap<T> &v1, BinaryHeap<T> &v2);
Any help will be much appreciated!
Z.Zen
Here is the declarations:
typedef int CBTNODE;
template <typename T>
class CompleteBinaryTree {
public:
//Initializes an empty binary tree
CompleteBinaryTree(int initialSize = 10);
//Destructor
~CompleteBinaryTree();
//Returns the element of the CBT pointed to by node. Behavior is undefined
//if node does not exist.
T element(CBTNODE node);
protected:
T *data;
int numElts, maxElts;
};
typedef pair<string, unsigned int> INDEX;
template <typename T>
class BinaryHeap : public CompleteBinaryTree<T>
{
public:
//Maintain heap property with bottom up heapify method.
void fixUp(CBTNODE hole);
};
bool operator>(INDEX &v1, INDEX &v2);
Implementation:
template <typename T>
T CompleteBinaryTree<T>::element(CBTNODE node) {
assert(node >= 0);
assert(node < numElts);
return data[node];
}
template <typename T>
void BinaryHeap<T>::fixUp(CBTNODE hole)
{
T tmp = this->element(hole);
while( hole > 0 && this->element(hole/2) < tmp )
{
//do stuff
}
}
bool operator>(INDEX &v1, INDEX &v2)
{
if(v1.second == v2.second) //if two have same relevance
{
return v1.first < v2.first;
}
return v1.second > v2.second;
}
A temporary, such as the result of element func, cannot be bound to a reference to non-const, such as the formal arguments of your operator>.
Declare it thusly:
bool operator>( INDEX const& v1, INDEX const& v2 )
However, the implementation that you present doesn't seem to be correct for operator>.
And while I'm at it, what you want is really operator< instead, because that's the one required by standard algorithms. Perhaps combined with an operator== (because it's inefficient to synthesize it from operator<). With those two any relationship can be checked for relatively efficiently.
Btw., if you stop using ALL UPPERCASE names for anything else then macros (see the FAQ), then you can avoid inadvertent name collision with macros.
Cheers & hth.,
Don't typedef INDEX, be explicit:
template<class F, class S>
struct Index {
std::pair<F, S> Value;
Index(const std::pair<F, S>& pValue)
: Value(pValue) {}
};
template<class F, class S>
bool operator<(const Index<F, S>& pLeft, const Index<F, S>& pRight) {
// your implementation...
}
I've declared a template class MyContainer as bellow, then created an instance of it of type DataType1. The DataType1 class provides a friend function "DataSpecificComparison" which is used by std::sort to compare DataType1 objects. The program compiled and sorted correctly.
I then defined a class called DataType2, gave it a friend implementation of "DataSpecificComparison" and used it to create another instance of MyContainer.
I am now unable to compile the program as a "C2914: 'std::sort' : cannot deduce template argument as function argument is ambiguous" compile time error is reported.
How can a developer specify that the DataSpecificComparison binary predicate is to take arguments of template type T*? Or is there another way around this issue?
template <class T>
class MyContainer
{
private:
vector<T*> m_vMyContainerObjects;
....
public:
....
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison)
}
}
class DataType1
{
....
friend bool DataSpecificComparison(const DataType1 * lhs, const DataType1 * rhs)
}
class DataType2
{
....
friend bool DataSpecificComparison(const DataType2* lhs, const DataType2* rhs)
}
You can use a temporary local function pointer variable of the required type to select the correct overload of DataSpecificComparison:
void SortMyContainerObjects()
{
typedef bool (*comparer_t)(const T*, const T*);
comparer_t cmp = &DataSpecificComparison;
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), cmp);
}
Here the compiler can deduce that you want to use the DataSpecificComparison overload that matches the comparer_t type, which resolves the ambiguity.
sth already gave a correct answer, but there's also a direct alternative based on the same principle:
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(),
static_cast<bool (*comparer_t)(const T*, const T*)>(&DataSpecificComparison));
}
This uses essentially the same mechanism. The cast forces overload resolution to happen before the Template Argument Deduction for std::sort.
template<typename T>
struct DataSpecificComp : public binary_function<T, T, bool>
{
public:
bool operator()(const T* lhs, const T* rhs)
{
return *lhs < *rhs;
}
};
call the sort function as shown below:
sort(vi.begin(), vi.end(), DataSpecificComp<int>());
I'd prefer something along the following lines: by default it compares objects with less_than (so you wouldn't have to remember to provide a function with a funny name), and there's an overload that allows giving your own comparison functor (again, value-based):
#include <vector>
#include <algorithm>
#include <functional>
template <class T, class Func>
struct indirect_binary_call_type: public std::binary_function<const T*, const T*, bool>
{
Func f;
indirect_binary_call_type(Func f): f(f) {}
bool operator()(const T* a, const T* b) const
{
return f(*a, *b);
}
};
template <class T, class Func>
indirect_binary_call_type<T, Func> indirect_binary_call(Func f)
{
return indirect_binary_call_type<T, Func>(f);
}
template <class T>
class MyContainer
{
private:
std::vector<T*> m_vMyContainerObjects;
public:
void Sort()
{
Sort(std::less<T>());
}
template <class Func>
void Sort(Func f )
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), indirect_binary_call<T>(f));
}
};
int main()
{
MyContainer<int> m;
m.Sort();
m.Sort(std::greater<int>());
}
Did you try defining DataSpecificComparison as template with bunch of specializations and giving it the type?
template<T>
bool DataSpecificComparison(const T* t1, const T* t2)
{
// something non compilable here
}
template<> bool DataSpecificComparison<Data1>(const Data1* t1, const Data1* t2)
{
// return *t1 < *t2;
}
....
void SortMyContainerObjects()
{
std::sort(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison<T>)
}
....
Templating DataSpecificComparison should work. You can also specifically call the proper std::sort template, but it's a bit cumbersome:
template <class T>
class MyContainer
{
private:
vector<T*> m_vMyContainerObjects;
typedef bool (*compsT)(T, T);
public:
....
void SortMyContainerObjects()
{
std::sort<std::vector<T*>::iterator, compsT>(m_vMyContainerObjects.begin(), m_vMyContainerObjects.end(), DataSpecificComparison);
}
}