#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);
}
给出以下错误:(try it)。
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}
因为它会降低可读性。
答案 0 :(得分:4)
那是因为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;}
相关规则是为什么参数类型a
可以在[basic.lookup.unqual] / 8中找到:
对于类X的成员,在成员函数体中使用的名称,在默认参数中,在例外规范中, 在非静态数据成员(9.2)的brace-or-equal-initializer中,或在类的定义中 在成员的declarator-id 之后,X的定义之外的成员应在其中一个中声明 以下方式:
- 在其使用的块中或在封闭块(6.3)中使用之前,或者 - 应为X类成员或X(10.2)基类的成员,或
返回类型a
与粗体文本(或上述任何文本)不匹配,但参数类型a
确实如此。
答案 1 :(得分:2)
如果是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;}