2015-07-05 48 views
2

我有一個模板函數的對象轉換爲字符串的向量(這是從圖書館,我無法改變這一點):專營模板任意類型

template <typename Q> std::wstring ToString(const Q& q) { static_assert(false, "Must specialise"); } 

現在,我要打電話它的參數爲std::vector<Gene>,其中Gene是一個簡單的類,其細節不重要。當然,要做到這一點,我需要專門的模板,所以我做的:

template<> std::wstring ToString(const std::vector<Gene>& q){...} 

假設我有另一個類,Cell,我想專門爲std::vector<Cell>ToString功能。我將不得不做出另一個明確的專業化,與std::vector<Gene>版本一樣。

用於將std::vector不依賴於實際的內容類型(int類型,一個Gene,一個Cell,另一std::vector等),所以這將是有意義的創建一個模板專業化,可與任何工作的邏輯std::vector。但我無法想出一個簡單的方法來做到這一點。目前,我目前有一個VectorToString函數,並轉發來自ToString(std::vector<Gene>>)ToString(std::vector<Cell>)的呼叫,但這仍然要求我爲每個元素類型實現專門化。

所以,對於實際的問題:是否有可能爲任意的std::vector創建一個專業化,我將如何做到這一點?而且,作爲獎勵問題,這可以推廣到任何支持std::beginstd::end的任意集合嗎?

我已經看過這個this question,並試圖宣稱這樣的專業化:

template<typename E> std::wstring ToString<std::vector<E>>(const std::vector<E>& t){...} 

但這種失敗C2768:非法使用顯式模板參數(「編譯器無法確定是否一個函數定義爲應該是一個函數模板的明確的專門化,或者如果函數定義應該是爲了一個新的函數。「),這是有道理的,因爲我們有相同的函數名稱和模板參數的數量,以及類似的簽名。

僅供參考,我使用的是Visual C++ 2015 RC,原始模板函數來自原生測試庫。

+0

不幸的是,您不能部分專門化功能,您正在_overloading_它們。 – grisha

回答

2

你幾乎做到了正確,但是在你不應該專門它們的功能的情況下,你應該簡單地重載它們像這樣:

template <typename Q> std::wstring ToString(const Q& q) { 
    return L"Original"; 
} 
template<typename E> std::wstring ToString(const std::vector<E>& t) { 
    return L"overload"; 
} 

一個運行示例,請參見http://ideone.com/G3r0Vt

這是可行的,因爲當選擇過載呼叫時,const std::vector<E>被認爲比const Q&「更好」,因此使用過載。

在代碼中使用這些方法時,應考慮ADL

+0

我曾嘗試過這樣的事情,但是因爲我認爲我是專精而不是重載,而且函數實際上是在一個命名空間中,所以我將它寫爲'template std :: wstring Microsoft :: VisualStudio :: CppUnitTestFramework :: ToString(const std :: vector &t)'這不起作用,我不得不用適當的'namespace'指令來包裝它。我注意到它也沒有任何命名空間,但我認爲最好的做法是在與原始函數相同的名稱空間中聲明重載。 – Meindratheal

2

我有你的下一個例子。嘗試下使用:

template<typename E> std::string ToString(const std::vector<E>& t) 
{ 
    std::stringstream resStr; 
    for (const E& element : t) 
    { 
     resStr << element << " "; 
    } 
    return resStr.str(); 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    std::vector<int> v1; 
    v1.push_back(22); 
    v1.push_back(33); 
    std::vector<double> v2; 
    v2.push_back(54.656); 
    v2.push_back(44.656); 
    auto strInt = ToString(v1); 
    auto strDouble = ToString(v2); 
    return 0; 
} 
0

我使用的基本類型的矢量如下:

namespace Microsoft 
{ 
    namespace VisualStudio 
    { 
     namespace CppUnitTestFramework 
     { 
      template<typename E> 
      std::wstring ToString(const std::vector<E> & t) 
      { 
       std::wstringstream result; 
       result << L"Size: " << t.size(); 

       if (t.size()) 
       { 
        result << L", Elements: "; 

        for (const auto & element : t) 
        { 
         result << L"{ " << element << L" } "; 
        } 
       } 
       return result.str(); 
      } 
     } 
    } 
} 

對於失敗的測試,你可以清楚地看到矢量的大小,它包含的元素。爲了您的目的,您可以使用:

namespace Microsoft 
{ 
    namespace VisualStudio 
    { 
     namespace CppUnitTestFramework 
     { 
      template<typename E> 
      std::wstring ToString(const std::vector<E> & t) 
      { 
       return L"Size: " + std::to_wstring(t.size()); 
      } 
     } 
    } 
}