C++模板类中成员函数的名称解析

C++ name resolution for member functions in template class

本文关键字:函数 成员 C++      更新时间:2023-10-16
#include <iostream>
template<class T> struct A {
    typedef T a; 
}; 
template<class T> 
struct B {
    typedef typename A<T>::a a;
    static a foo(a b); 
}; 
template<class T> 
a B<T>::foo(a b) {return b}
int main() {
    std::cout << B<int>::foo(1); 
}

给出以下错误:(尝试一下)。

main.cpp:13:1: error: 'a' does not name a type
    a B<T>::foo(a b) {return b}

内联定义不会受到此错误的影响。

有人可以解释为什么编译器在这种情况下无法解决a,以及我如何使这段代码工作。

我不想明确解决所有名称,例如

typename B<T>::a B<T>::foo(typename B<T>::a b) {return b}

因为它会降低可读性。

这是因为这里的a仍在全局范围内查找:

template<class T> 
a B<T>::foo(a b) {return b;}
^^

您正在对a进行不合格的查找。到达定义的B<T>::部分后,该范围将添加到所有进一步的查找中。因此,b参数的类型将在B<T>范围内查找。

您只需将其限定为返回类型:

template<class T> 
typename B<T>::a B<T>::foo(a b) {return b;}

相关规则是为什么可以在 [basic.lookup.unqual]/8 中找到参数类型a

对于类 X 的成员,成员函数体、默认参数、异常规范中使用的名称, 在非静态数据成员 (9.2) 的大括号或等于初始值设定项中,或在类的定义中 在 X 定义之外的成员,在成员的声明者 ID 之后,应在 以下方式:
— 在使用它的块或封闭块中使用之前 (6.3),或
— 应是 X 类的成员或 X 类基本类的成员 (10.2),或

返回类型 a 与粗体文本(或上面的任何文本)不匹配,但参数类型 a 匹配。

如果C++11和14,则可以声明函数auto以摆脱长返回类型。您需要在 C++11 中将其指定为尾随类型,但这允许您省略typename B<T>::,因为编译器已经知道要查找的位置。

//C++11
template<class T>
auto B<T>::foo(a b) -> a {return b;}
//C++14
template<class T>
auto B<T>::foo(a b) {return b;}