2017-02-13 56 views
2

我想專用非模板類中的單個模板方法來使用std::vector,但只有方法的返回類型使用該模板。如何專門化模板方法與類型本身是一個模板,其中只有返回類型依賴於模板類型?

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

class Foo 
{ 
public: 
    template<typename T> 
    T Get() 
    { 
     std::cout << "generic" << std::endl; 
     return T(); 
    } 
}; 

template<> 
int Foo::Get() 
{ 
    std::cout << "int" << std::endl; 
    return 12; 
} 

template<typename T> 
std::vector<T> Foo::Get() 
{ 
    std::cout << "vector" << std::endl; 
    return std::vector<T>(); 
} 

int main() 
{ 
    Foo foo; 
    auto s = foo.Get<std::string>(); 
    auto i = foo.Get<int>(); 
} 

這將編譯與指示std::vector試圖專業化不匹配的任何Foo原型,這是完全可以理解的錯誤。

萬一它很重要,使用C + + 14是好的,丹迪。

+2

贊[this](http://coliru.stacked-crooked.com/a/a1af61a9d5725a51)?我沒有得到你期望的語法。 –

+0

你不能部分地專注於C++的功能 - 所以'template std :: vector '不允許 – PiotrNycz

回答

4

您只能部分專業化類(結構)(cppreference) - 所以解決您的問題的方法是添加幫助程序結構以允許std::vector<T>的部分專業化 - 例如,這種方式:

class Foo 
{ 
private: // might be also protected or public, depending on your design 
    template<typename T> 
    struct GetImpl 
    { 
     T operator()() 
     { 
      std::cout << "generic" << std::endl; 
      return T(); 
     } 
    }; 
public: 
    template<typename T> 
    auto Get() 
    { 
     return GetImpl<T>{}(); 
    } 
}; 

對於int - 你可以完全專注此功能:

template<> 
int Foo::GetImpl<int>::operator()() 
{ 
    std::cout << "int" << std::endl; 
    return 12; 
} 

對於std::vector<T>你有專攻整個結構:

template<typename T> 
struct Foo::GetImpl<std::vector<T>> 
{ 
    std::vector<T> operator()() 
    { 
     std::cout << "vector" << std::endl; 
     return std::vector<T>(); 
    } 
}; 
+0

nitpick:GetImpl應該是私人的 – Caleth

+0

@Caleth - 確定它可以,並且一般情況下它應該是私有的。 – PiotrNycz

2

不能部分specialze模板在C++中。你需要重載你的函數並傳入參數中的類型。

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

class Foo 
{ 
public: 
    template<typename T> 
    T Get() 
    { 
     return this->getTemplate(static_cast<T*>(0)); // 
    } 
private: 
    template<class T> T getTemplate(T* t) 
    { 
     std::cout << "generic" << std::endl; 
     return T(); 
    } 
    template<class T> std::vector<T> getTemplate(std::vector<T>* t) 
    { 
     std::cout << "vector" << std::endl; 
     return std::vector<T>(); 
    } 
}; 

template <> int Foo::getTemplate(int* t) 
{ 
    std::cout << "int" << std::endl; 
    return 12; 
} 
int main() 
{ 
    Foo foo; 
    auto s = foo.Get<std::string>(); 
    auto i = foo.Get<int>(); 
    auto v = foo.Get<std::vector<int>>(); 
} 

編輯:固定在代碼

+1

由@PiotrSkotnicki提出的實際標記看起來更清晰並且處理更多類型(作爲參考)。 – Jarod42

+0

關於處理更多類型,這兩個方法處理所有T和std :: vector ,同時允許特定類型專業化。 你能詳細說明爲什麼它看起來更清潔嗎? – Clonk

+0

您不處理'int&',指針是常規類型(例如可以引用它)。 '標籤'是專用的。 – Jarod42

3

template功能(包括成員函數)Partial specialisation一個錯字是不允許的。一種選擇是使用SFINAE代替超載。例如,

/// auxiliary for is_std_vetor<> below 
struct convertible_from_std::vector 
{ 
    template<typename T> 
    convertible_from_std::vector(std::vector<T> const&); 
}; 

template<typename V> 
using is_std_vector 
    = std::is_convertible<V,convertible_from_std_vector>; 

class Foo 
{ 
public: 
    template<typename T, std::enable_if_t< is_std::vector<T>::value,T> 
    Get() 
    { 
     std::cout << "vector" << std::endl; 
     return T(); 
    } 
    template<typename T, std::enable_if_t<!is_std::vector<T>::value,T> 
    Get() 
    { 
     std::cout << "generic" << std::endl; 
     return T(); 
    } 
}; 

注意,輔助類is_std_vector可以在其他情況下也是有用的,所以值得擁有它的地方。還要注意,您可以通過要求任何std::vector或特定的std::vector<specific_type, specific_allocator>來使此幫助類更具多功能性。例如,

namespace traits { 
    struct Anytype {}; 
    namespace details { 
     /// a class that is convertible form C<T,T> 
     /// if either T==AnyType, any type is possible 
     template<template<typename,typename> C, typename T1=Anytype, 
               typename T2=Anytype> 
     struct convCtTT 
     { 
      convCtTT(C<T1,T2> const&); 
     }; 

     template<template<typename,typename> C, typename T1=Anytype> 
     struct convCtTT<C,T1,AnyType> 
     { 
      template<typename T2> 
      convCtTT(C<T1,T2> const&); 
     }; 

     template<template<typename,typename> C, typename T2=Anytype> 
     struct convCtTT<C,AnyType,T2> 
     { 
      template<typename T1> 
      convCtTT(C<T1,T2> const&); 
     }; 

     template<template<typename,typename> C> 
     struct convCtTT<C,AnyType,AnyType> 
     { 
      template<typename T1, typename T2> 
      convCtTT(C<T1,T2> const&); 
     }; 
    } 
    template<typename Vector, typename ValueType=AnyType, 
           typename Allocator=AnyType> 
    using is_std_vector 
     = std::is_convertible<Vector,details::convCtTT<std::vector,ValueType, 
                   Allocator>; 
} 
相關問題