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

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

基本上,我想让一个函数针对 vector (类型)参数和非 vector 类型参数表现不同。

#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。

但由于 is_vector(int)::value 返回 false,为什么我的编译器会报告“'.front' 的左边必须有类/结构/union ”?我怎样才能让它工作?

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

我需要递归调用读取函数,同时将多维 vector 作为模板参数传递,但编译器禁止我这样做。

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)))?)

最佳答案

你想要一个函数模板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>如果type,第二个将无法编译不是一些 std::vector<U> .有用的是,编译器选择了它可以编译的那个。 那叫 SFINAE ("Substitution Failure Is Not An Error") , 这是您的问题的解决方案。

这是一个说明性程序:

#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 see live )

关于C++ 如何使用 vector<T> 专门化模板?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40626433/

相关文章:

c++ - 为什么范围算法在比较器参数之后有投影参数?

nlp - 我想创建一个系统,我给出一个句子,系统会吐出与我给出的输入句子含义相似的句子

rust - 将未声明的类型名称错误与参数化特征一起使用

c++ - 创建脚本扩展器

c++ - 如何在不使用 new 的情况下使在其他对象中创建的对象保持事件状态?

java - 如何指定 Antlr4 中表达式大小的大小?

syntax - 编程语言语法中尾随逗号的历史

generics - 在通用变量中存储嵌套特征实例

PHP:类中的特征与其他特征冲突

c++ - 引用每个 const 字符串是一种好习惯吗?