Смущен из-за вложенного зависимого имени типа C ++ - PullRequest
0 голосов
/ 21 ноября 2018

Эффективный C ++ сказал мне, что лучше использовать typename при обнаружении вложенного имени зависимого типа.

Следующий пример кода легко понять:

template <typename ElementType>
class BST {
private:
  class LinkNode {
  public:
    ElementType data;
    LinkNode *left, *right;
    explicit LinkNode() {}
  };

public:
  void some_func();
}

template <typename ElementType>
void BST<ElementType>::some_func() {
  // or `using NodePtr = typename BST<ElementType>::LinkNode *;`
  typedef typename BST<ElementType>::LinkNode * NodePtr;
  ...
}

Однако после того, как я добавил использование псевдонимов в классе шаблона BST, казалось, что ключевое слово typename больше не является необходимым.

Здесь вы можете видеть:

template <typename ElementType>
class BST {
private:
  class LinkNode {
  public:
    ElementType data;
    LinkNode *left, *right;
    explicit LinkNode() {}
  };

  using NodePtr = LinkNode *; // the only difference between these two code blocks

public:
  void some_func();
}

template <typename ElementType>
void BST<ElementType>::some_func() {
  // typename is not neccessary here!
  BST<ElementType>::NodePtr ptr;
  ...
}

Кто-нибудь может это выяснить?

1 Ответ

0 голосов
/ 21 ноября 2018

Этот эффект не связан напрямую с псевдонимом типа через using, это результат поиска имени для члена текущей реализации.

Внутри BST оба выражения BST и BST<ElementType> относятся к текущему экземпляру, и его члены можно найти без использования префикса typename, который вы можете сделать:

template <typename ElementType>
void BST<ElementType>::some_func() {
    BST::NodePtr ptr; // or 
    BST<ElementType>::LinkNode * ptr2;
}

в результате чего то же самое.Но теперь давайте предположим, что some_func также является функцией-членом шаблона, определенной как:

template <typename ElementType>
struct BST {
    class LinkNode { /*...*/ };

    using NodePtr = LinkNode *;

    template <typename T>
    void some_func();
};


template <typename ElementType>
template <typename T>
void BST<ElementType>::some_func() {
    BST<T>::NodePtr ptr;     // (1)
    BST<T>::LinkNode * ptr2  // (2)
}

Теперь ни (1), ни (2) не будут компилироваться, потому что B<T> больше не является текущей реализацией, следовательно, вв этих случаях вам нужно typename.

Соответствующая часть стандарта [temp.res]/7:

В пределах определения шаблона класса или в определении члена классаВ шаблоне, следующем за идентификатором объявления, ключевое слово typename не требуется при обращении к имени ранее объявленного члена шаблона класса, который объявляет тип или шаблон класса.[...]

...