2015-06-19 77 views
1
#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)。模板类中成员函数的C++名称解析

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

http://stackoverflow.com/questions/1643035/propagating-typedef-from-based-to-derived-class-for-template and http://stackoverflow.com/questions/1567730/inheritance-and-templates -in-c-why-are-methods-invisible似乎是相关的。 – marc

回答

4

这是因为这里的a在全球范围内仍在寻找:

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

你在做a查找unqualifed。一旦找到定义的B<T>::部分,该范围就会添加到所有进一步查找中。所以在B<T>的范围内查找参数b的类型。

您只需要限定它的返回类型:

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

的相关规则是为什么参数类型a可以发现在[basic.lookup.unqual/8:

For the members of a class X, a name used in a member function body, in a default argument, in an exceptionspecification, in the brace-or-equal-initializer of a non-static data member (9.2), or in the definition of a class member outside of the definition of X, following the member’s declarator-id, shall be declared in one of the following ways:
— before its use in the block in which it is used or in an enclosing block (6.3), or
— shall be a member of class X or be a member of a base class of X (10.2), or

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

+0

参数类型不在成员函数体中。这是“在X定义之外的类成员定义之后,遵循成员的* declarator-id *”。 –

+0

@ T.C。谢谢,纠正。 – Barry

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