Это ситуация, когда я хотел бы использовать «использование»? - PullRequest
2 голосов
/ 23 июня 2011

Я не знаком с C ++ 0x. Я только начал изучать C ++ около 6 месяцев назад, хотя у меня достаточно сильные познания (для начинающих).

У меня есть шаблонный класс:

template <typename T>
class Node
{
   ...
}

Тогда позже у меня есть это:

template <typename T>
class BinaryTree
{
    protected:
       typedef Node<T>* node_t;
    ...
}

Здесь класс бинарного дерева служит «базовым классом», который может быть расширен специализациями бинарных деревьев. (Дерево AVL, Красно-черный и т. Д.) Узел typedef защищен, поскольку идея заключается в том, что специализации смогут использовать его ... и могут, но это выглядит довольно ужасно.

Например, в моем классе BiTree (мое творческое имя для наиболее общего двоичного дерева, в основном BST), у нас есть это:

template <typename T>
class BiTree : public BinaryTree<T>
{
   private:
      typedef typename BinaryTree<T>::node_t node_t; // Yuck
   ...
}

Что еще хуже, я один из тех, кто любит указывать функции вне класса, поэтому, когда я хочу сказать, что node_t - это тип возвращаемого значения ... ну, взгляните ...

template <typename T>
typename BiTree<T>::node_t
BiTree<T>::insert(BiTree<T>::node_t& node, T data)
{
   ...
}

Есть ли способ просто использовать node_t? В этом и заключался весь смысл наследования typedef от базового класса. Для этого ли ключевое слово using в C ++ 0x? Как бы я применил это к этой ситуации? Благодаря.

РЕДАКТИРОВАТЬ: причина, по которой мне интересно, если это полезно, из-за этого вопроса: шаблон C ++ typedef

Ответы [ 2 ]

8 голосов
/ 23 июня 2011

Ответ на ваш вопрос - нет, он не применим. using в контексте, который вы имеете в виду, предназначен для переименования шаблонного типа при сохранении его шаблонного характера. Вы имеете в виду конкретный экземпляр шаблона, поэтому он не подходит.

Однако, часть вашего беспокойства, кажется, просто переизбыток BiTree<T>:: в вашем определении функции. Это не так уж плохо для меня; вы привыкли видеть подобные конструкции. Но это может быть уменьшено, если вы хотите.

С чего вы начали:

template <typename T> 
typename BiTree<T>::node_t BiTree<T>::insert(BiTree<T>::node_t& node, T data) 
{ ... } 

Прежде всего, когда вы называете функцию, вы уже «внутри» класса BiTree<T>, поэтому компилятор будет искать внутри него типы ваших аргументов.

template <typename T> 
typename BiTree<T>::node_t BiTree<T>::insert(node_t& node, T data) 
{ ... } 

Другая новая особенность C ++ 0x - возможность ждать объявления функции до тех пор, пока после вы не объявите ее аргументы. Он предназначен для использования в ситуациях, когда тип результата зависит от типов аргументов, но он полезен и здесь по той же причине, что и выше. Компилятор будет рассматривать типы в BiTree<T> при анализе:

template<typename T>
auto BiTree<T>::insert(node_t& node, T data) -> node_t
{ ... }

Почти нет повторений. Технически вы можете пойти еще дальше:

template<typename T>
auto BiTree<T>::insert(node_t& node, T data) 
     -> std::remove_reference<decltype(node)>::type
{ ... }

Теперь вы даже не повторяете тип параметра, но получить правильный тип возвращаемого значения заметно сложнее [о чем свидетельствует тот факт, что я изначально ошибся; -)].

1 голос
/ 23 июня 2011

Ehm ... в производном классе доступны определения типа базового класса без фокусировки, просто используйте node_t (хотя _t - это неправильный суффикс , поскольку все имена, заканчивающиеся на нем, зарезервированыпо стандарту POSIX).Но мне интересно, почему вы делаете это protected / private, если хотите вернуть такой узел из insert?Как это следует использовать, поскольку никто за пределами иерархии классов не может использовать node_t?

...