嵌套 类 中 g++ 和 clang++ 之间的不同行为

Different behavior between g++ and clang++ in nested classes

我注意到 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. 正确的语法是什么?

正确的语法如下:

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

您可以在 this 问题中找到此语法的完整解释。

但是,更简单且有效的语法是:

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

通过在上面的示例中使用尾随的 return 类型语法,您可以利用名称解析范围在 Outer<T>::Inner<S> 内的事实,因此您可以使用 injected class name Inner.