2016-07-15 47 views
0

我面臨的情況是出現了兩個有關ADL和模板功能專業化在某些情況下如何工作的問題。模板函數在類模板中的明確的朋友專業化

  1. 爲什麼我不能用COUT朋友專業化的定義裏面? 在這種情況下我收到一個鏈接錯誤,指出basic_stream未定義,但如果我切換到調用cat編譯繼續。

    template<class T> 
    void func1(T&){ 
        ... 
    } 
    
    void cat(){ cout << "foo.func1" <<endl; } 
    
    namespace first{ 
        template<class R> 
        struct foo{ 
         friend void func1<>(foo<int>&){ 
          cout << "foo.func1" <<endl; // cat(); 
         }   
        };  
    } 
    
    foo<int> f; 
    func1(f); 
    
  2. 爲什麼ADL當我改變專業化指模板類PARAM不適? 如果我對ADL技工沒有任何錯誤,爲了解決func1在3中調用的正確版本(例如global(1)或friend defined one(2)),它會收集所有可能的匹配並選擇最具體的一。而且,我認爲最具體的一個是版本func1,因爲不是將函數參數指定爲完全依賴於模板參數,而是指定具體類型foo,其中func1不在1中,但ADL選擇func1無論如何。這是爲什麼 ?

    template<class T> 
    void func1(T&){  // 1 
        ... 
    } 
    
    namespace first{ 
        template<class R> 
        struct foo{ 
         friend void func1<>(foo<R>&){  // 2 
          cout << "foo.func1" <<endl; 
         }   
        };  
    } 
    
    foo<int> f; 
    func1(f);  // 3 
    
+0

你的意思是'第一:: foo的 F; '? – aschepler

+0

我不認爲這段代碼有效。我得到了「錯誤:在朋友聲明中定義顯式專門化'func1'」。 http://coliru.stacked-crooked.com/a/728b83afb9b416a4 – aschepler

+0

代碼不應該編譯,你使用的編譯器是什麼? – Barry

回答

1

模板參數無關與朋友的聲明。你需要隨身攜帶他們在friend聲明消除歧義:

template<class R> 
struct foo{ 
    template<typename U> 
    friend void func1<U>(foo<U>&){ 
     cout << "foo.func1" <<endl; // cat(); 
    }   
};  

也爲你的情況,你應該決定,如果你想要把如上內聯朋友定義,或者只是提供了一個聲明:

template<class R> 
struct foo{ 
    template<typename U> 
    friend void ::func1<U>(foo<U>&); 
};  

後者應明確匹配在全局命名空間的friend模板功能,並可以根據需要進行專業化:

template<> 
void func1(int&){ 
    // ... 
} 

template<> 
void func1(std::string&){ 
    // ... 
} 

// a.s.o. 
+0

我相信你的第一個例子是不合格的,ndr。 – Barry

+0

謝謝,從模板類param中分離好友聲明參數使其有效。 – xhamr

+0

@巴里,是的,它是部分的,但將部分「func1 」更改爲「func1」,並保留其他部分原樣,修復「無部分專業化錯誤」的問題,這是你所指的。 – xhamr

1

你不需要提供func1的專業化。只需提供過載:

namespace first { 
    template <class R> 
    struct foo { 
     friend void func1(foo&){ 
      std::cout << "foo.func1" << std::endl; 
     } 
    }; 
} 

int i; 
first::foo<int> f; 

func(i); // calls ::func<int> 
func1(f); // calls first::func1(first::foo<int>&); 

否則,你可以朋友specizliation,但你不能定義在類體內專業化:

template <class R> 
struct foo { 
    friend void func1<>(foo&); // friends ::func1<foo<R> > 
}; 
+0

「但你不能在類體中定義專業化」。@Barry如果你看看第一種情況,專業化是使用foo 而不是foo &而且編譯失敗,因爲它在鏈接時找不到「cout」,但如果使用「printf」,編譯成功和朋友專業化被選中。 – xhamr

+0

@xhamr 1)這不是編譯失敗,這是一個鏈接器錯誤2)由於明確的特殊化,代碼將無法編譯......或者至少會有ODR問題。方式更容易過載。 – Barry

+0

@xhamr對不起,不一定編譯失敗。請參見[\ [temp.expl.spec \]](http://eel.is/c++draft/temp.expl.spec#6)。 – Barry