【问题标题】:How to know if a type is a specialization of std::vector?如何知道一个类型是否是 std::vector 的特化?
【发布时间】:2013-04-26 14:23:39
【问题描述】:

我整个上午都在处理这个问题,但没有任何结果。 基本上,我需要一个简单的元编程东西,如果传递的参数是std::vector,我可以分支到不同的专业。

某种is_base_of 用于模板。

这样的事情存在吗?

【问题讨论】:

  • “专业化”是指继承吗?还是类型别名(例如typedef)?还是针对某种类型的专门实现(如std::vector<bool> 是)?
  • 你的问题很模糊:如果你想确定一个类型是否是一个类型的 std::vector 的模板特化,你不应该这样做(无论如何都不是干净的方式) .如果您想确定一个类型是否从 std::vector 继承,则明确建议不要这样做(std::vector 没有虚拟析构函数并且不应该被继承,只能被封装)。如果要确定类/typedef/template 参数是否为 std::vector,则应使用模板化特征类(请参阅 jrok 的答案)。
  • @utnapistim:一般来说,检查一个类型是否是模板的特化并不困难
  • @DavidRodríguez-dribeas - 我的意思不是检查一个类型是否是 std::vector,而是有一个模板 类 vector 特定的实现(类似于struct is_std_vector<std::vector<T,A>> 如何是 jirok 回答中 struct is_std_vector 的具体实现)。有没有办法做到这一点?
  • @utnapistim:我想这只是一个误解,因为在标准含义中过度使用了“专业化”一词,无论是对于一组模板参数都有单独的定义,而且类型/替换基本模板中的模板参数后生成的函数。 AFAIK 你是对的,因为你无法检测到一组特定的模板参数是否有不同的定义。

标签: c++ templates metaprogramming template-specialization


【解决方案1】:

在 C++11 中,您还可以采用更通用的方式:

#include <type_traits>
#include <iostream>
#include <vector>
#include <list>

template<typename Test, template<typename...> class Ref>
struct is_specialization : std::false_type {};

template<template<typename...> class Ref, typename... Args>
struct is_specialization<Ref<Args...>, Ref>: std::true_type {};


int main()
{
    typedef std::vector<int> vec;
    typedef int not_vec;
    std::cout << is_specialization<vec, std::vector>::value << is_specialization<not_vec, std::vector>::value;

    typedef std::list<int> lst;
    typedef int not_lst;
    std::cout << is_specialization<lst, std::list>::value << is_specialization<not_lst, std::list>::value;
}

【讨论】:

  • 嗨!这个例子怎么能改成支持具有非类型模板参数的 std::array 呢?
  • 不,我不这么认为。这是因为没有通用机制既可以是类型名也可以是值类型,并且可以保存类型或具体值。抱歉,我认为你必须编写一个特殊的 is_std_array 模板。
  • 很好的例子。如果对于初学者来说,这将是很好的解释
  • 为了教化,甚至有人提议添加这种泛型类型特征,请参阅proposal p2098r1
  • 实现起来很烦人,为什么标准库中没有?
【解决方案2】:

如果你需要一个 trait 类,这很简单,你只需要一个通用模板和对任何 std::vector 的特化:

#include <type_traits>
#include <iostream>
#include <vector>

template<typename>
struct is_std_vector : std::false_type {};

template<typename T, typename A>
struct is_std_vector<std::vector<T,A>> : std::true_type {};

int main()
{
    typedef std::vector<int> vec;
    typedef int not_vec;
    std::cout << is_std_vector<vec>::value << is_std_vector<not_vec>::value;
}

【讨论】:

  • 为了完整起见,您实际上应该专门针对 vector&lt;T,A&gt; 来使用自定义分配器捕获向量。
  • 另请注意:实现允许添加额外的模板参数,因此您可能需要检查。尽管上面的代码会检测向量的每个实例,这些实例使用可能的附加模板参数的默认值。
  • 如果你想捕获所有的扩展,你可以使用template &lt;typename T, typename... Ts&gt; struct is_std_vector&lt;std::vector&lt;T, Ts...&gt;&gt; : std::true_type { }
  • @DavidRodríguez-dribeas 好消息!经过一番考古,我发现the original message by Daniel Krügler 为我指明了正确的方向。反过来,该消息链接到Issue 94 of the Standard Library,带我们回到 1998 年。(愚蠢地我开始研究 语言 问题...)
  • @LucDanton:与一些委员会成员重新检查,他们确认最初的意图是支持额外的模板参数,但是当模板模板参数实际实现(在语言级别)时,他们发现它不能做不完。就像现在一样,标准库中的类型不允许带任何额外的参数。
【解决方案3】:

不,但您可以使用仅接受 std::vector&lt;T&gt; 的模板函数重载。在这种情况下,编译器会选择最专业的模板。

【讨论】:

    【解决方案4】:

    在 C++ 11 中,有一种简单的方法可以检查 T 是否为向量:

    std::is_same<T, std::vector<typename T::value_type>>::value;
    

    【讨论】:

      猜你喜欢
      • 2012-10-01
      • 1970-01-01
      • 2011-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多