Различное поведение между g ++ и clang ++ во вложенных классах - PullRequest
0 голосов
/ 09 февраля 2020

Я заметил другое поведение между gcc 9.2.0 и clang++ 9.0.1. Мой код выглядит следующим образом:

//header.hh
     ...
template <typename T>
class Outer {
     ...
  public:
     template <typename S>
     class Inner;
     ... 
};

template <typename T>
template <typename S>
class Inner {
     ...
      Inner& func();
     ...
};

, так как функция func() реализована в другом файле

//implementation.cc
template <typename T>
template <typename S>
Outer<T>::Inner<S>& Outer<T>::Inner<S>::func() {
    ...
};

Теперь, если я использую g++, компиляция в порядке. Если я использую clang++, я получаю

src/implementation.cc:6:1: error: missing 'typename' prior to dependent type template name 'Outer<T>::Inner'
Outer<T>::Inner<S>& Outer<T>::Inner<S>::func() {
^
1 error generated.

Однако, если я последую его предложению и использую

typename Outer<T>::Inner<S>& Outer<T>::Inner<S>::func()

, я получу еще одну ошибку:

src/implementation.cc:6:21: error: use 'template' keyword to treat 'Inner' as
a dependent template name typename Outer<T>::Inner<S>& Outer<T>
::Inner<S>::func() {

И теперь его предложение кажется очень странным.

ВОПРОСЫ

  1. Почему два компилятора ведут себя по-разному?
  2. Какой правильный синтаксис использовать?

1 Ответ

1 голос
/ 09 февраля 2020

Правильный синтаксис будет следующим:

template <typename T>
template <typename S>
typename Outer<T>::template Inner<S> &Outer<T>::Inner<S>::func() {
    ...
}

Полное объяснение этого синтаксиса можно найти в этом вопросе.

Однако проще и также допустим следующий синтаксис:

template <typename T>
template <typename S>
auto Outer<T>::Inner<S>::func() -> Inner& {
    ...
}

Используя синтаксис конечного типа возврата в приведенном выше примере, вы можете воспользоваться тем фактом, что область разрешения имени находится в пределах Outer<T>::Inner<S>, поэтому вы можете используйте введенное имя класса из Inner.

...