2017-02-13 69 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>; 
}