1。符號(hào)查找(對(duì)于函數(shù)此時(shí)只看名字,不看參數(shù))
大致順序是
(1)如果有限定名( XXX:: )那么就直接在XXX里查找
(2)函數(shù)局部名字空間
(3)(如果是成員)類名字空間
(4)遞歸向上至所有基類的名字空間
(5)當(dāng)前名字空間
(6)遞歸向外至所有外層名字空間,
在任一層里, 用using導(dǎo)入的符號(hào)和該層的其他符號(hào)同一對(duì)待。
keonig查找: 對(duì)于函數(shù), 如果參數(shù)為類/結(jié)構(gòu)/模版類并位于其他的名字空間,
在(5)和(6)的查找中導(dǎo)入該空間(不遞歸向外)的符號(hào)一同查找.
2。(如果是函數(shù))重載決議(注意此時(shí)特化的函數(shù)不參與決議)
3。(如果是類內(nèi)部的名字)檢查訪問權(quán)(注意此時(shí)特化的函數(shù)仍然不參與決議)
4。(如果找到了一個(gè)模版)模版特化決議
編譯器執(zhí)行以上步驟的時(shí)候是使用貪心匹配,只要找到一個(gè)符合當(dāng)前檢查內(nèi)容的就會(huì)停止查
找
所以任何一層都有可能發(fā)生錯(cuò)誤的掩蓋情況
例1
1
void f( int )
{}
2
class Y
3
{
4
public :
5
void f()
{}
6
Y()
7
{
8
f( 1 );
9
}
10
} ;
這里的f(2)在1.(2)這里找到了符號(hào)f,就不會(huì)向上到1.(5)查找到真正的f(int)了
例2
void g( int )
{}
namespace S

{

void g()
{}
void h()

{
g( 1 );
}
}
這里的g(1)在1.(5)這里找到了符號(hào)g,就不會(huì)向上到1.(6)查找到真正的g(int)了
例3
class Y

{

void f( int )
{} // [1]
public :

void f( double )
{} // [2]
} ;

int main()

{
Y y;
y.f( 1 );
}
y.f(1)會(huì)調(diào)用[2]嗎?不會(huì),因?yàn)樵诘?步重載決議的時(shí)候就選定[1]了,因此這段代碼會(huì)報(bào)
出無法訪問private成員的錯(cuò)誤
例4
template < typename T >
void f(T)
{} // [1]
template < typename T >
void f(T * )
{} // [2]
template <>
void f < int *> ( int * )
{} // [3]
int main()

{
int * p = 0 ;
f(p);
}
這里的f(p)會(huì)調(diào)用[3]嗎?
不會(huì),因?yàn)樵谶M(jìn)行到第二步重載決議的時(shí)候,只有[1]和[2]參與了重載決議,結(jié)果選擇了
[2],那么[1]的特化版本[3]當(dāng)然就輪不到了。
例5
class X

{

template < typename T > void g()
{}
public :

template <> void g < int > ()
{}
} ;

int main()

{
X y;
y.g < int > ();
}
這里首先第3步訪問檢查發(fā)現(xiàn)g為private(此時(shí)g的特化版本被直接無視了),所以即使
g<int>為public, 該段代碼仍然不能夠編譯通過
例6
namespace E

{

class X
{} ;

void f(X)
{} // [1]
}
void f(E::X)
{} // [2]
class X

{
public :

void f()
{} // [3]
void g()

{
E::X x;
f(x); // [4]
}
} ;

[4]會(huì)調(diào)用那個(gè)呢? 在1.(3)里就確定了是[3],因此參數(shù)不匹配
如果注釋掉[3]的f,那么由于koenig查找, 在1.(5)里[1]和[2]都會(huì)是平等的可選項(xiàng)
所以會(huì)出現(xiàn)二義性.
如果把namespace E改為class E, 把E中的f改為靜態(tài)函數(shù)
由于koenig查找僅僅導(dǎo)入?yún)?shù)的名字空間, 因此[1]將不參與1.(5)的查找,
最終結(jié)果會(huì)是[2]
例7
這是一個(gè)現(xiàn)實(shí)中的例子,如果想給std::pair寫一個(gè)ostream的輸出函數(shù),應(yīng)該如何實(shí)現(xiàn)呢?
template<class U, class V>
ostream& operator<<(ostream& s, const pair<U, V>& p)


{
return s << p.first << " : " << p.second;
}
差不多該這樣吧
但是如下代碼就會(huì)導(dǎo)致出錯(cuò)
map<string, string> a;
copy(m.begin(), m.end(), ostream_iterator<pair<string, string> >(s, "\n"));
為什么呢?
因?yàn)樵趏stream_iterator的實(shí)現(xiàn)代碼里調(diào)用了pair的operator<<
由于ostream_iterator的代碼是在std名字空間里的,因此編譯器會(huì)首先在std里查找是否存在operator<<
一旦找到(盡管找到的operator<<不是給pair使用的),就不會(huì)繼續(xù)到全局名字空間里查找我們自己定義的operator<<了
因此解決方案是把自定義的operator<<放到std名字空間里
namespace std
{
template<class U, class V>
ostream& operator<<(ostream& s, const pair<U, V>& p)
{
return s << p.first << " : " << p.second;
}
}
就可以了
例8
傳說中的hide
struct A
{
void f(int){}
};
struct B: public A
{
void f(void){}
};
int main()
{
B b;
b.f(1);
}
b.f(1)能編譯通過嗎?不能,因?yàn)榫幾g器會(huì)首先在B的名字空間里查找f,找到了void f(void),然后就會(huì)停止查找
因此A里的f(int)根本就沒有機(jī)會(huì)被編譯器訪問到
posted on 2006-12-27 11:04
shifan3 閱讀(2133)
評(píng)論(8) 編輯 收藏 引用 所屬分類:
C++