2015-06-19 34 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;}