如何使用类型专用化模板方法,该类型本身就是一个模板,其中只有返回类型依赖于模板类型



我想在非模板类中专门化单个模板方法来使用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很好,很花花公子。

您只能部分专用化类(结构((cpp首选项( - 因此克服问题的方法是添加辅助结构以允许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>();
    }
};

不允许对template函数(包括成员函数(进行部分专用化。一种选择是重载而不是使用 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>;
}

你不能在 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>>();
}

编辑:修复了代码中的拼写错误

最新更新