2016-04-29 113 views
2

鑑於此代碼:模板重載麻煩

#include <string> 
#include <vector> 
#include <iostream> 

template <typename T> 
std::string stringify(const T&) { 
    return "{?}"; 
} 

template <typename T> 
std::string proxy(const T& in) { 
    return stringify(in); 
} 

// trying to specialize "stringify()" 

template <typename T> 
std::string stringify(const std::vector<T>& in) { 
    return "vector specialization!"; 
} 

template <> 
std::string stringify(const std::vector<int>& in) { 
    return "INT vector specialization!"; 
} 

int main() { 
    std::cout << proxy(1); // calls the 1st 

    std::vector<int> intVec; 
    std::cout << proxy(intVec); // calls the 1st 

    std::vector<double> dblVec; 
    std::cout << proxy(dblVec); // calls the 1st 

    return 0; 
} 

我怎樣才能proxy<>後專門爲stringify()vector<>

目前我得到{?}{?}{?}

如果我刪除這一個 - stringify(const std::vector<T>& in)那麼vector<int>開始變得調用,因爲這將是第一的專業化。

然後我會得到{?}INT vector specialization!{?}

有什麼辦法調用任何的2矢量專業化字串功能從proxy() - 如果它們被定義最後 - 在proxy()功能之後?

有沒有辦法部分專注於vector<>並仍然從proxy<>打電話?

我不想專門爲vector<int>vector<double>vector<UserType> ...

編輯:忘了提我需要這個C++98

回答

3

首先,避免專業函數模板,更喜歡超載。有關潛在隱患,請參閱Herb Sutter's article。其次,您遇到的問題涉及名稱查找如何在函數模板中爲從屬名稱起作用。裏面proxy<T>stringify是一個獨立的名字 - 它取決於T。該名稱將在模板的定義點(它將找到stringify<T>(const T&)而不是其他重載)和在參數的相關名稱空間(將是std)的實例化處重新查找。這些查找都沒有找到你的其他功能。

這是查找的第二部分 - 依賴於參數的查找 - 我們可以利用。讓我們只是堅持在一個命名空間中的一切(這我命名N隨意,隨時根據情況重新命名):

namespace N { 
    struct helper { }; 

    template <typename T> 
    std::string stringify(helper, const T&) { 
     return "{?}"; 
    } 
} 

template <typename T> 
std::string proxy(const T& in) { 
    return stringify(N::helper(), in); 
} 

好了,到目前爲止,我們已經改變絕對沒有。在所有情況下我們仍然得到{?}。但現在我們仍然可以在該命名空間但proxy定義後的stringify堅持進一步重載(不是特例):

namespace N {  
    template <typename T> 
    std::string stringify(helper, const std::vector<T>&) { 
     return "vector overload!"; 
    } 

    std::string stringify(helper, const std::vector<int>&) { 
     return "INT vector overload!"; 
    } 
} 

這兩個重載將通過名稱查找,因爲N的第二階段中找到是一個關聯的命名空間helper。現在proxy(intVFec)將找到stringify的所有三種重載,而不僅僅是一種。現在您的代碼打印:

{?}INT vector overload!vector overload! 

根據需要。以上都不需要C++ 11。

+0

非常感謝!你救了我的屁股!我喜歡它,當C++魔術工作,我不明白它 - 仍然試圖不學習ADL :)生命是短暫的。 – onqtam

+0

@onqtam ADL是非常重要的 - 畢竟它是如何'標準:: cout <<「你好,世界!」'工作! – Barry

+0

剛剛發現,這不能在VC++ 6下編譯...也許ADL是壞的(只有當使用模板重載!免費函數重載罰款) - 它說在'''代理()'''如果有超過1個專業化,該調用是不明確的。也許是時候放棄對它的支持 – onqtam