【问题标题】:C++ How to specialize a template using vector<T>?C ++如何使用vector<T>专门化模板?
【发布时间】:2016-11-16 07:37:18
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

  • 您对向量的检查是运行时检查。该分支中的所有代码仍然必须是可编译的。
  • 首先:is_vector 谓词在编译时进行评估。在 if 中使用它表明您没有完全理解应该使用什么模板。
  • @Albjenow 我对元编程了解不多,如何让我的函数为向量和 pod 类型生成不同的代码?
  • 作为您问题的一种可能解决方案,您可能希望专门化 read 函数:一个通用非向量变体,一个用于std::vector
  • @Someprogrammerdude 谢谢。在非向量变体中,我只使用一个类型名,在向量变体中,我需要专门化向量并使用 T 作为它的 value_type ,所以这是两个类型名,如何实现这一目标?

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


【解决方案1】:

您需要一个至少参数化的函数模板foo&lt;R&gt; 通过返回类型R,你想要一个专门的实现 当R = std::vector&lt;U&gt;,为任意类型U

foo&lt;R&gt; 的参数可能是什么并不重要,所以为了说明 我们假设没有。这样做的方法如下:

定义一个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&lt;U&gt;,对于某些U,将在编译时为真。

然后在以下几行中定义foo&lt;R&gt;() 的两个重载:

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&lt;R&gt;::value 为假时,第一个重载才是合法代码。这 当且仅当is_vector&lt;R&gt;::value 为真时,第二个重载才是合法代码。 这要归功于std::enable_if 的行为, 你应该学习和理解。

当编译器需要选择一个这些模板重载来实现一些 调用它在您的代码中找到的foo&lt;type&gt;(),它发现正是其中一个重载 当模板参数R 插入type 时甚至不会编译。如果第一个将无法编译 type 是一些 std::vector&lt;U&gt; 并且如果 type 是一些 not 则第二个将不会编译 std::vector&lt;U&gt;。有用的是,编译器会选择它可以编译的那个。 那叫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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-13
    相关资源
    最近更新 更多