C ++如何使用vector <t>来专门化模板?

时间:2016-11-16 07:37:18

标签: c++ grammar traits template-meta-programming

基本上,我想让一个函数对矢量(类型)参数和非矢量类型参数的行为有所不同。

#include <vector>
using namespace std;

template <typename type>
struct is_vector {
    static const bool value = false;
};

template <typename type>
struct is_vector<vector<type>>
{
    static const bool value = true;
};
template <typename type>
type read()
{
    if (is_vector<type>::value)
    {       
        type vec(10);
        vec.front()=1;//left of '.front' must have class/struct/union   
        return vec;
    }
    else
    {
        return{};
    }
}
int main()
{
    auto i= read<int>();
}

我想在使用vector作为typename时返回一个向量,在使用int作为typename时返回一个int。

但是因为is_vector(int):: value返回false,为什么我的编译器会报告&#39;。#front;#39;必须有class / struct / union&#34; ?我怎样才能使它发挥作用?

我想要实现的是将字符串正确反序列化为向量(类型)或向量(向量(类型))。

我需要递归调用read函数,同时传递multidemonsional向量作为模板参数,但编译器禁止我这样做。

template <typename type>
struct is_vector {
    static const bool value = false;
};

template <typename type>
struct is_vector<vector<type>>
{
    static const bool value = true;
};

template <typename type>
type read(char*& str)
{
    if (is_vector<type>::value)
    {       
        type vec(read<uint8_t>(str));
        for (auto& e : vec)
            e = read<type::value_type>(str);
        return vec;
    }
    return *reinterpret_cast<type*>((str += sizeof(type)) - sizeof(type));
}

所以我尝试了专业化。

template<>
vector<int> read<vector<int>>(char*& str)
{
    vector<int> vec(read<uint8_t>(str));
    for (auto& e : vec)
        e = read<int>(str);
    return vec;
}//works 

template <typename type>
template <>
vector<type> read<vector<type>>(char*& str)
{
    vector<type> vec(read<uint8_t>(str));
    for (auto& e : vec)
        e = read<type>(str);
    return vec;
}//don't work

我真的需要为我使用的每种类型手动重写我的读取函数吗?

(像vector(vector(vector(int)))?)

1 个答案:

答案 0 :(得分:2)

您需要至少参数化的函数模板foo<R> 通过返回类型R,您需要一个专门的实现 当R = std::vector<U>时,对于任意类型U

foo<R>的论点可能并不重要,所以为了说明 我们假设没有任何东西。以下是您的表现方式:

定义 trait 模板,如下所示:

template<typename T>
struct is_vector
{
    static constexpr bool value = false;
};

template<template<typename...> class C, typename U>
struct is_vector<C<U>>
{
    static constexpr bool value = 
        std::is_same<C<U>,std::vector<U>>::value;
};

有了这个,

is_vector<T>::value
当且仅当T = std::vector<U>时,对于某些U

在编译时才会成立。

然后在以下行中定义foo<R>()的两个重载:

template <typename R>
std::enable_if_t<!is_vector<R>::value,R> foo()
{
    // Your non-vector implementation instead of...
    std::cout << 
        "In non-vector specialization of `foo<R>()`\n";
    return R();
}

template <typename R>
std::enable_if_t<is_vector<R>::value,R> foo()
{
    // Your vector implementation instead of...
    std::cout << 
        "In vector specialization of `foo<R>()`\n";
    return R();
}

这两个过载是相互排斥的,并且是相互详尽的。该 当且仅当is_vector<R>::value为假时,第一次重载才会成为合法代码。该 当且仅当is_vector<R>::value为真时,第二次重载才会成为合法代码。 这要归功于std::enable_if的行为, 你应该学习和理解。

当编译器需要选择一个这些模板重载来实现一些 调用它在代码中找到的foo<type>(),它会发现其中一个重载 在插入type模板参数R时,甚至无法编译。第一个不会编译,如果 如果type 某些std::vector<U>,那么typestd::vector<U>,第二个不会编译 #include <vector> #include <type_traits> #include <iostream> template<typename T> struct is_vector { static constexpr bool value = false; }; template<template<typename...> class C, typename U> struct is_vector<C<U>> { static constexpr bool value = std::is_same<C<U>,std::vector<U>>::value; }; template <typename R> std::enable_if_t<!is_vector<R>::value,R> foo() { // Your non-vector implementation instead of... std::cout << "In non-vector specialization of `foo<R>()`\n"; return R(); } template <typename R> std::enable_if_t<is_vector<R>::value,R> foo() { // Your vector implementation instead of... std::cout << "In vector specialization of `foo<R>()`\n"; return R(); } int main() { auto i = foo<int>(); (void)i; auto vc = foo<std::vector<char>>(); (void)vc; return 0; } 。有用的是,编译器会选择它可以编译的那个。 这被称为SFINAE ("Substitution Failure Is Not An Error"), 它解决了你的问题。

这是一个说明性的程序:

In non-vector specialization of `foo<R>()`
In vector specialization of `foo<R>()`

将输出:

-std=c++14

(gcc 6.1 / clang 3.8,QAPlug see live