C ++如何使用vector< T>来专门化模板? [英] C++ How to specialize a template using vector<T>?

查看:67
本文介绍了C ++如何使用vector< T>来专门化模板?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本上,我想使一个函数对vector(type)参数和非vector类型参数的行为有所不同.

Basicly ,I want to make a function behave differently for a vector(type) parameter and a non-vector type parameter .

#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作为类型名时返回一个vector,在使用int作为类型名时返回一个int.

I want to return a vector while using vector as the typename ,return an int while using int as the typename .

但是由于is_vector(int):: value返回false,为什么我的编译器会报告'.front'的左边必须有class/struct/union"?如何使它工作?

But since is_vector(int)::value returns false ,why would my compiler reports "left of '.front' must have class/struct/union" ?How can I make it work ?

我想要实现的是正确地将字符串反序列化为vector(type)或vector(vector(type)).

What I want to achieve is to correctly deserialize a string to a vector(type) or a vector(vector(type)) .

我需要递归地调用read函数,同时传递一个多维向量作为模板参数,但是编译器禁止我这样做.

I need to recursively call the read function ,while passing a multidemonsional vector as a template parameter ,but the compiler forbids me to do it .

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

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

Do I really need to manually rewrite my read function for every kind of types I use ?

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

(like vector(vector(vector(int)))?)

推荐答案

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

You want a function template foo<R> that is parameterized at least by return type R, and you want a specialized implementation when R = std::vector<U>, for arbitrary type U.

foo< R> 的参数可以是什么都没有关系,因此出于说明目的我们假设没有任何东西.这是您的操作方式:

It doesn't matter what the arguments of foo<R> may be, so for illustration we'll assume there aren't any. Here's how you do that:

定义一个 trait 模板,如下所示:

Define a trait template as follows:

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 )时,

在编译时为true.

will be true at compiletime if and only if T = std::vector<U>, for some U.

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

Then define two overloads of foo<R>() on the following lines:

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 为false时,第一次重载才会成为合法代码.这仅当 is_vector< R> :: value 为true时,第二次重载才会成为合法代码.这要归功于 std :: enable_if ,您应该学习和理解的.

These two overloads are mutually exclusive and jointly exhaustive. The first overload pans out to be legal code if and only if is_vector<R>::value is false. The second overload pans out to be legal code if and only if is_vector<R>::value is true. That's thanks to the behaviour of std::enable_if, which you should study and understand.

当编译器需要选择一个时,这些模板重载可以实现一些调用在您的代码中找到的 foo< type>(),它发现恰好是重载之一为模板参数 R 插入 type 时,甚至都不会编译.如果第一个不会编译 type 是一些 std :: vector< U> ,如果 type not ,则第二个不会编译一些 std :: vector< U> .有用的是,编译器选择了可以编译的那个.这就是 SFINAE (替换失败不是错误"),这就是您的问题的解决方案.

When the compiler needs to pick one these template overloads to implement some call foo<type>() that it finds in your code, it discovers that exactly one of the overloads won't even compile when type is plugged in for the template parameter R. The first one won't compile if type is some std::vector<U> and the second one won't compile if type is not some std::vector<U>. Helpfully, the compiler picks the one that it can compile. That's called SFINAE ("Substitution Failure Is Not An Error"), and it's the solution of your problem.

这是一个说明性程序:

#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;
}

它将输出:

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

(gcc 6.1/clang 3.8, -std = c ++ 14

(gcc 6.1/clang 3.8, -std=c++14 see live)

这篇关于C ++如何使用vector&lt; T&gt;来专门化模板?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆