有没有一种方法可以通过数组类型专门化功能模板?

时间:2020-04-16 08:46:01

标签: c++ c++11 templates

比方说,我们需要一个函数模板,该模板应根据类型返回整数:

template<typename T>
int get_type();

此外,我们将其专门化为几种类型:

template<>
int get_type<int>()
{
  return TYPE_INT;
}

// And so on for other types...

这很好用,但不适用于数组类型。我可以执行以下操作:

template<>
int get_type<char[]>()
{
  return TYPE_STRING;
}

,编译器对此表示“同意”,但链接器不同意。因为类型char[]不同于例如char[5]

有什么方法可以在没有功能参数的情况下实现功能模板?也就是说,我知道我们可以做这样的事情:

template<typename T>
int get_type(const T&);

但是,实际上,这里不需要(使用)功能参数。

编辑:

我使用C ++ 11。

4 个答案:

答案 0 :(得分:9)

您不能对模板函数进行部分专业化(但是您可以对模板类进行专门化

另一种方法是使用重载而不是专门化来进行标签分配:

template <typename> struct Tag{};

constexpr int get_type(Tag<int>) { return TYPE_INT; }

template <std::size_t N>
constexpr int get_type(Tag<char[N]>) { return TYPE_STRING; }

template <typename T>
constexpr int get_type() { return get_type(Tag<T>{}); }

答案 1 :(得分:8)

您需要部分专业化才能解决可变数组长度的问题,并且C ++不允许部分专业化的功能模板。规范的解决方案是(部分)专门化具有(静态)成员(函数)的类模板,并从您未专门设计的函数模板中将其分发给您:

namespace detail {
    template <typename T>
    struct get_type;

    template <>
    struct get_type<int> {
        static constexpr int value = TYPE_INT;
    };

    template <>
    struct get_type<char> {
        static constexpr int value = TYPE_CHAR;
    };

    template <typename T, std::size_t N>
    struct get_type<T[N]> {
        static constexpr int value = get_type<T>::value | TYPE_ARRAY;
    };

    template <std::size_t N>
    struct get_type<char[N]> {
        static constexpr int value = TYPE_STRING;
    };
} // namespace detail

template<typename T>
constexpr int get_type() {
    return detail::get_type<T>::value;
}

答案 2 :(得分:6)

您不能部分专用于具有大小的数组的函数。但是您可以在课堂上做到这一点。

template<typename T>
class type
{
    static int get_type();
};

template<>
struct type<int>
{
    static int get_type() { return 1; }
};

template<size_t SZ>
struct type<char[SZ]>
{
    static int get_type() { return 2; }
};

template<typename T>
int get_type() { return type<T>::get_type(); }

int main()
{
    std::cout << get_type<char[3]>() << std::endl;
    return 0;
}

example

答案 3 :(得分:3)

我认为Konrad已经描述了最佳方法。

这是由SFINAE提供支持的另一种具有超载和专业化的方法

// overload 1, for non-array types
template<typename T>
std::enable_if_t<!std::is_array_v<T>, int> get_type();

// specialization of overload 1 for int
template <>
auto get_type<int>() -> int {
    return 1;
}

// overload 2, for array types
template <typename T>
auto get_type() -> std::enable_if_t<std::is_array_v<T>, int> {
    return 3;
}