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

时间:2015-06-19 14:52:13

标签: c++ templates

#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}

因为它会降低可读性。

2 个答案:

答案 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;}