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

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

本文关键字:之间 clang++ g++ 嵌套      更新时间:2023-10-16

我注意到gcc9.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() {
...
}

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

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

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

通过使用上面示例中的尾随返回类型语法,您可以利用此时名称解析范围在Outer<T>::Inner<S>范围内的事实,以便您可以使用Inner的注入类名。