【问题标题】:Create is_primitive or is_inheritable template创建 is_primitive 或 is_inheritable 模板
【发布时间】:2013-03-21 00:56:27
【问题描述】:

我想创建一个模板来检查类类型是否为原始类型(int、char、float、float*** 等...)。这样做的原因是为了防止另一个模板尝试扩展原语并导致编译时错误。到目前为止,我有一些类似的东西:

#include <typeinfo>
template<typename T>
struct is_primitive{
   const static bool value=std::is_fundamental<T>::value;
};

显然,这只是现在转发 is_fundamental 的结果。我想添加 remove_pointer、remove_reference 等...以去除输入类的所有这些额外修饰符。 为了使 T 尽可能裸露,需要删除哪些内容?

另外,类似以下的解决方案也同样出色:

template<typename T>
struct is_inheritable{
   const static bool value=???;
};

但我很确定不可继承类的集合等于原始类的集合。

【问题讨论】:

  • 听起来你想要is_fundamental。请注意(如您的问题中所写),类类型永远不是原始(基本),因为始终通过classstruct 引入类类型。
  • 哇,我不知道为什么我错过了它,但我认为它没有捕捉到所有我可能不知道的引用、指针部分和其他东西(对真实的 C++ 世界)。我会用 is_fundamental 更新我的问题。
  • T 的“baring”通常称为Unqualified&lt;T&gt;,链接RemoveCv&lt;RemoveReference&lt;T&gt;&gt; 就足够了——引用不能是 cv 限定的,所以它们必须在顶层。您不能拥有对引用的引用或指向引用的指针,因此它们必须位于顶层。之后,只需剥离 cv-qualificaiton。 (Cv 限定意味着 const 和/或 volatile 限定。)
  • 您能否更具体地说明一下为什么首先需要这个?可能是一种更简单的方法。
  • @Aggieboy:经典XY problem。你的解决方案不是一个好的解决方案,因为它肯定不能解决问题。即使忽略您假设存在 vtable 指针(C++ 不需要的实现细节)这一事实,我也可以通过在某些 C++ 编译器上传递一个空类来轻松破坏您的代码。空类必须有大小,但空基优化意味着派生类可以与基类大小相同,即使有额外的 vtable 指针。

标签: c++ templates c++11 std


【解决方案1】:

听起来你想要std::is_class&lt;T&gt;。只能从类类型继承。这是描述 C++11 类型分类特征的图表:Here http://howardhinnant.github.io/TypeHiearchy.pdf

http://howardhinnant.github.io/TypeHiearchy.pdf

【讨论】:

  • 这很棒。自 2007 年以来有什么变化会导致它过时吗? (编辑:例如,is_signed split 缺失;有目的的、疏忽的还是过时的?)
  • @GManNickG:我没有仔细检查过,但我认为没有。请注意,此图仅对 20.9.4.1 主要类型类别和 20.9.4.2 复合类型特征进行建模。前者描述了 3.9 类型中的所有“叶子”类型,后者描述了这棵树中的非叶子类型。 is_signed 以及许多其他特征进入 20.9.4.3 类型属性,此图中均未表示。一个预期的不变量是 C++ 中的每种类型都恰好适合一个主要类型类别(上图中的叶子)。
  • 哇,这回答了我除了 OP 之外的更多问题,哈哈。我选择了这个,因为它非常简洁和信息丰富。
  • @JohannesSchaub-litb:这部分分类是在 3.9.2 复合类型 [basic.compound] 之后构建的。 p1 中的每个子弹都有一个叶子。并且能够区分类和联合肯定会派上用场。例如。没有它你就无法实现std::throw_with_nested。我们本可以让is_class 成为is_unionis_non_union_class 的“或”,但这看起来很尴尬和迂腐到让人分心的地步。
  • @TrevorHickey:typedef void F(); 中的F 是一个函数。 std::is_function&lt;F&gt;::value 是真的。 std::is_pointer&lt;F&gt;::value 是假的。 typedef void (*FP)(); 中的 FP 是指向函数的指针。 std::is_function&lt;FP&gt;::value 是假的。 std::is_pointer&lt;FP&gt;::value 是真的。 std::is_function&lt;std::remove_pointer&lt;FP&gt;::type&gt;::value 是真的。
【解决方案2】:

我建议您尝试专注于检测在您的情况下需要可继承的类型的属性,而不是考虑检测那些不可继承的类型。运气好的话,您的类需要基类中可以检查的其他属性,因为您的派生类将需要调用至少一个基类的构造函数。

尝试使用is_constructible 或一些相关的类型特征:

// check that T::T(std::string,int); exists:
std::is_constructible< T, std::string, int >::value

// or these direct traits for the usual suspects...
std::is_default_constructible< T >::value
std::is_copy_constructible< T >::value
std::is_move_constructible< T >::value

对于您的其他问题,如果在上述之后仍然相关,请查看 std::decay 并将其与其他特征结合以根据需要剥离类型:

template< typename T, typename = void >
struct strip
{
     typedef T type;
};

template< typename T >
struct strip< T, typename std::enable_if<
  !std::is_same< typename std::decay< T >::type, T >::value
>::type >
    : strip< typename std::decay< T >::type >
{
};

template< typename T >
struct strip< T, typename std::enable_if<
  std::rank< T >::value != 0
>::type >
    : strip< typename std::remove_all_extents< T >::type >
{
};

template< typename T >
struct strip< T, typename std::enable_if< std::is_pointer< T >::value >::type >
    : strip< typename std::remove_pointer< T >::type >
{
};

typedef const int*(&Test)[42];
static_assert( std::is_same< typename strip< Test >::type, int >::value, "" );

但当然,您需要弄清楚什么才是适合您的情况。

【讨论】:

    【解决方案3】:
    template <typename T>
    struct remove_all { typedef typename std::remove_cv<T>::type type; };
    template <typename T>
    struct remove_all<T*> { typedef typename remove_all<T>::type type; };
    template <typename T>
    struct remove_all<T&> { typedef typename remove_all<T>::type type; };
    template <typename T>
    struct remove_all<T&&> { typedef typename remove_all<T>::type type; };
    
    template<typename T>
    struct is_primitive{
        typedef typename remove_all<T>::type TF;
        const static bool value=std::is_fundamental<TF>::value;
    };
    

    找到here的remove_all struct讨论。

    【讨论】:

    • std::cout &lt;&lt; std::is_same&lt; remove_all&lt; int*const &gt;::type, int* &gt;::value -- 你的remove_all 被误导了?
    • 它应该删除所有指针和引用属性,但是我对 const 之类的 cvs 有点懒惰。所以它应该变成 int*const -> int,但是我认为后缀 const 搞砸了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-09
    • 1970-01-01
    相关资源
    最近更新 更多