Use member types to declare variable

  • Thread starter Thread starter TylerH
  • Start date Start date
  • Tags Tags
    Member Variable
AI Thread Summary
The discussion centers on the use of member types in STL containers, particularly in the context of declaring variables. It highlights that member types like key_type are primarily intended for use in custom container templates, where the specific type of keys is not known. For typical usage, such as with a map<int, char>, developers can directly use int for key-related operations without needing to reference key_type.The conversation also touches on the development of a custom container, specifically a trie that utilizes a map for storage. A participant shares code snippets demonstrating how to define a node class and a trie class, emphasizing the need for typedefs to simplify type declarations, particularly for iterators. This approach enhances code readability and maintainability, especially when changing the underlying container type. The discussion concludes with a public domain release of the trie implementation, showcasing practical applications of the concepts discussed.
TylerH
Messages
729
Reaction score
0
The STL containers have a lot of member types, so I assume they must be there for declaring variables of those types. However, I can't discern how exactly it is that I'm supposed to use those member types to declare a variable.

For example:
Code:
map<int, char> t;

t::key_type u; // I want this to mean "int u." That is the purpose of the member type, isn't it?
 
Technology news on Phys.org
The reason for key_type etc is to make the library code hardware-independent and general-purpose, not necessarily for you to use directly.

The only time you would want to declare a variable of type key_type is if you were building your own contaner template based on map, or something similar. In that case, you don't know what type the key will be, and also you don't know how the map class represents keys internally. (For example the code that implements the map might treated all keys as bit strings, indepedent of what variable type the user declared them to be).

If your code declares and uses a map<int, char> to store data (and that is the most common way that application programs use the container classes), you know the keys for your paticular map are ints (because you declared them to be that!), and you can use int variables for anything to do with keys.
 
AlephZero said:
The only time you would want to declare a variable of type key_type is if you were building your own contaner template based on map, or something similar. In that case, you don't know what type the key will be, and also you don't know how the map class represents keys internally. (For example the code that implements the map might treated all keys as bit strings, indepedent of what variable type the user declared them to be).
That's exactly what I'm doing. I'm developing a container (trie) that uses a map for underlying storage.

Code:
#ifndef NODE_H
#define NODE_H

#include <functional>
#include <iterator>
#include <map>
#include <tuple>

template<typename T, typename... U>
class node
{
	public:
	node() : _value(nullptr) {}

	void erase(std::iterator<std::forward_iterator_tag, T> start, std::iterator<std::forward_iterator_tag, T> end)
	{
		typename std::map<T, node<T, U...>>::iterator t = _subnodes.find(*start);
		// more stuff
	}

	typedef T key_type;
	typedef std::tuple<U...> value_type;

	private:
	T _key;
	std::tuple<U...> *_value;
	std::map<T, node<T, U...>> _subnodes;
};

#endif // NODE_H
I could type "typename std::map<T, node<T, U...>>::iterator" every time, but that's an insanely long type and it do any good if I decide to change _subnodes from map to something else. Is there any other way?
 
I could type "typename std::map<T, node<T, U...>>::iterator" every time, but that's an insanely long type and it do any good if I decide to change _subnodes from map to something else. Is there any other way?

Why not define a typedef for the typename?

Code:
typedef typename std::map<T, node<T, U...>>::iterator trie_iterator;
or whatever you want to call it.
 
I finally took the time to finish it. Here it is if anyone wants to use it. It's public domain.
Code:
#include <algorithm>
#include <iterator>
#include <map>
#include <memory>
#include <utility>

template<class T, typename U>
class trie
{
	public:
	trie() : _root(_data) {}

	typedef typename std::map<T, U>::iterator iterator;
	typedef typename std::map<T, U>::reverse_iterator reverse_iterator;

	iterator begin()
	{
		return _data.begin();
	}

	iterator end()
	{
		return _data.end();
	}

	reverse_iterator rbegin()
	{
		return _data.rbegin();
	}

	reverse_iterator rend()
	{
		return _data.rend();
	}

	inline void erase(const T &key)
	{
		_root.erase(key.begin(), key.end());
	}

	inline iterator find(const T &key)
	{
		return _root.find(key.begin(), key.end());
	}

	inline std::pair<iterator, bool> insert(const T &key, const U &value)
	{
		auto t = _data.insert(std::pair<T, U>(key, value));
		_root.insert(key.begin(), key.end(), t.first);
		return t;
	}

	protected:
	class subtrie
	{
		public:
		subtrie(std::map<T, U> &data) : _data(data) {}

		inline void erase(const T &key)
		{
			erase(key.begin(), key.end());
		}

		void erase(typename T::const_iterator begin, typename T::const_iterator end)
		{
			typename std::map<typename T::const_iterator::value_type, subtrie>::iterator t = _subtries.find(*begin);
			begin++;
			if(begin != end)
				t->second.erase(begin, end);
			else
				_subtries.erase(t);
		}

		inline iterator find(const T &key)
		{
			return find(key.begin(), key.end());
		}

		iterator find(typename T::const_iterator begin, typename T::const_iterator end)
		{
			if(begin != end)
			{
				typename std::map<typename T::const_iterator::value_type, subtrie>::iterator t = _subtries.find(*begin);

				if(t != _subtries.end())
				{
					begin++;
					return t->second.find(begin, end);
				}
				else
					return _data.end();
			}
			else
				return _it;
		}

		inline void insert(iterator it)
		{
			insert(it->first.begin(), it->first.end(), it);
		}

		void insert(typename T::const_iterator begin, typename T::const_iterator end, const iterator it)
		{
			if(begin != end)
			{
				typename std::map<typename T::const_iterator::value_type, subtrie>::iterator t = _subtries.insert(typename std::map<typename T::const_iterator::value_type, subtrie>::value_type(*begin, subtrie(_data))).first;
				begin++;
				t->second.insert(begin, end, it);
			}
			else
				_it = it;
		}

		private:
		iterator _it;
		std::map<T, U> &_data;
		std::map<typename T::const_iterator::value_type, subtrie> _subtries;
	};

	private:
	subtrie _root;
	std::map<T, U> _data;
};
 
Dear Peeps I have posted a few questions about programing on this sectio of the PF forum. I want to ask you veterans how you folks learn program in assembly and about computer architecture for the x86 family. In addition to finish learning C, I am also reading the book From bits to Gates to C and Beyond. In the book, it uses the mini LC3 assembly language. I also have books on assembly programming and computer architecture. The few famous ones i have are Computer Organization and...
I had a Microsoft Technical interview this past Friday, the question I was asked was this : How do you find the middle value for a dataset that is too big to fit in RAM? I was not able to figure this out during the interview, but I have been look in this all weekend and I read something online that said it can be done at O(N) using something called the counting sort histogram algorithm ( I did not learn that in my advanced data structures and algorithms class). I have watched some youtube...
Back
Top