Reputation: 3031
I'm not familiar with C++0x. I just started learning C++ myself about 6 months ago, I have a fairly strong grasp though (for a beginner).
I have a templated class:
template <typename T>
class Node
{
...
}
Then later, I have this:
template <typename T>
class BinaryTree
{
protected:
typedef Node<T>* node_t;
...
}
Here, the Binary tree class is serving as a "base class" that can be extended by specializations of binary trees. (AVL Tree, Red-Black, etc.,) The node typedef is protected, because the idea is the specializations will be able to use it...and they can, but it looks pretty awful.
For example, in my BiTree class (my creative name for the most generic binary tree, basically a BST), we have this:
template <typename T>
class BiTree : public BinaryTree<T>
{
private:
typedef typename BinaryTree<T>::node_t node_t; // Yuck
...
}
To make matters worse, I'm one of those people who likes to specify functions outside of a class, so when I want to say node_t is the return type...well, have a look...
template <typename T>
typename BiTree<T>::node_t
BiTree<T>::insert(BiTree<T>::node_t& node, T data)
{
...
}
Is there a way to just use node_t? That was sort of the whole point of inheriting the typedef from the base class. Is this what the using
keyword in C++0x is for? How would I apply it to this situation? Thanks.
EDIT: The reason I'm wondering if it's useful is because of this question: C++ template typedef
Upvotes: 2
Views: 251
Reputation: 10969
The answer to your question is no, it isn't applicable. using
in the context you mean is intended for renaming a templated type while retaining its templated nature. You have a specific instance of the template in mind, so it is not appropriate.
However, part of your concern seems to simply be the overabundance of BiTree<T>::
in your function definition. It doesn't seem that bad to me; you get used to seeing constructs like that. But it can be reduced if you want.
What you started with:
template <typename T>
typename BiTree<T>::node_t BiTree<T>::insert(BiTree<T>::node_t& node, T data)
{ ... }
First of all, once you name the function, you're already "inside" the class BiTree<T>
, so the compiler will look inside it for types of your arguments.
template <typename T>
typename BiTree<T>::node_t BiTree<T>::insert(node_t& node, T data)
{ ... }
Another new feature of C++0x is the ability to wait to declare the result of a function until after you declare its arguments. It is intended for use in situations where the type of the result depends on the types of the arguments, but it is useful here as well for the same reason as above. The compiler will consider types within BiTree<T>
when analyzing it:
template<typename T>
auto BiTree<T>::insert(node_t& node, T data) -> node_t
{ ... }
Almost no repetition. You can technically go one step further:
template<typename T>
auto BiTree<T>::insert(node_t& node, T data)
-> std::remove_reference<decltype(node)>::type
{ ... }
Now, you don't even repeat the parameter type, but getting the return type correct is notably more difficult [as evidenced by the fact that I got it wrong initially ;-)].
Upvotes: 8
Reputation: 131799
Ehm... base class typedefs are available in the derived class without any hocus pocus, just use node_t
(though _t
is a bad suffix, as all names ending in it are reserved by the POSIX standard). But I'm wondering, why do you make it protected
/ private
if you want to return such a node from insert
? How should that be used, as nobody outside of the class hierarchy can use the node_t
?
Upvotes: 1