美文网首页
C++ traits使用

C++ traits使用

作者: lypxhxjj | 来源:发表于2018-08-27 19:38 被阅读0次
  1. traits一般是利用编译器的能力来获取一些信息。采取的实现方案是模板与模板特化。

  2. 实现细节:模板类与static成员变量。

----》都是使用模板类来实现的;

----》模板类中都有一个静态成员变量,是模板参数的typedef;

----》这些行为都是编译器确定的,不是运行期,所以没有效率问题。

  1. 基础实现细节:
    (1)消除const属性,消除volatile属性:
template< class T >
struct remove_cv {
    typedef typename std::remove_volatile<typename std::remove_const<T>::type>::type type;
};
 
template< class T > struct remove_const          { typedef T type; };
template< class T > struct remove_const<const T> { typedef T type; };       //偏特化实现;
 
template< class T > struct remove_volatile             { typedef T type; };
template< class T > struct remove_volatile<volatile T> { typedef T type; }; 

(2)判断两个类型是否相同

template<class T, class U>
struct is_same : std::false_type {};            //有一个内部静态变量value是false;
 
template<class T>
struct is_same<T, T> : std::true_type {};       //偏特化实现

(3)integral_constant类型:所有traits的基类

template<class T, T v>                  //参数是类型T和T类型变量的值;
struct integral_constant {
    static constexpr T value = v;       //里面有个静态成员变量T value = v;
    typedef T value_type;
    typedef integral_constant type; // using injected-class-name
    constexpr operator value_type() const noexcept { return value; }
    constexpr value_type operator()() const noexcept { return value; } //since c++14
};

----》比如我想要类内部的static变量是true,即

typedef std::integral_constant<bool, true> true_type ; 
  1. 判断类型是否是某个类型:
template< class T >
struct is_void : std::is_same<void, typename std::remove_cv<T>::type> {};

类似的实现:
判断是否为空指针类型:

template< class T >
struct is_null_pointer : std::is_same<std::nullptr_t, std::remove_cv_t<T>> {};

判断是否float类型:

template< class T >
struct is_floating_point
     : std::integral_constant<
         bool,
         std::is_same<float, typename std::remove_cv<T>::type>::value  ||
         std::is_same<double, typename std::remove_cv<T>::type>::value  ||
         std::is_same<long double, typename std::remove_cv<T>::type>::value
     > {};

左值右值的判断:

template <class T> struct is_rvalue_reference      : std::false_type {};
template <class T> struct is_rvalue_reference<T&&> : std::true_type {};


template<class T> struct is_lvalue_reference     : std::false_type {};
template<class T> struct is_lvalue_reference<T&> : std::true_type {};

很多其他is_的判断比较复杂,可以需要的时候再研究。(与类型相关的时候都可以研究)

  1. 迭代器中traits的使用。
    迭代器中定义了一个__type_traits来说明一个类的信息,以决定算法具体采用什么策略来实现。
template <typename type>
struct __type_traits {
    //不要移除
    typedef __true_type this_dummy_member_must_be_first;
 
    //trivial指无意义的
    typedef __false_type has_trivial_default_constructor;
    typedef __false_type has_trivial_copy_constructor;
    typedef __false_type has_trivial_assignment_constructor;
    typedef __false_type has_trivial_destructor;
    typedef __false_type is_POD_type;
    //POD指的是这样一些数据类型:基本数据类型、指针、union、数组、
    //构造函数是 trivial 的 struct 或者 class

然后针对C++现有的各种类型,定义__type_traits的全特化版本来实现,如:(当然没有实现偏特化的类型都是按上面的定义)

//特化版本
template <>
struct __type_traits<char> {
    typedef __true_type has_trivial_default_constructor;
    typedef __true_type has_trivial_copy_constructor;
    typedef __true_type has_trivial_assignment_constructor;
    typedef __true_type has_trivial_destructor;
    typedef __true_type is_POD_type;
};
template <class T>
struct __type_traits<T*> {
    typedef __true_type has_trivial_default_constructor;
    typedef __true_type has_trivial_copy_constructor;
    typedef __true_type has_trivial_assignment_constructor;
    typedef __true_type has_trivial_destructor;
    typedef __true_type is_POD_type;
}

算法实现时可以根据如下方式来判断到底是否可以使用更简单的方式来实现算法。

template <class InputIterator, class ForwardIterator, class T>
inline ForwardIterator
__uninitialized_copy(InputIterator first, InputIterator last,
                     ForwardIterator result, T*) {
  typedef typename __type_traits<T>::is_POD_type is_POD;                //用来判断是不是POD类型
  return __uninitialized_copy_aux(first, last, result, is_POD());       //不是根据if来判断调用哪个逻辑;而是根据函数模板参数的类型来判断:是true_type还是false_type;
}

根据是否是是POD类型,分别实现:

// Valid if copy construction is equivalent to assignment, and if the
//  destructor is trivial.
template <class InputIterator, class ForwardIterator>
inline ForwardIterator 
__uninitialized_copy_aux(InputIterator first, InputIterator last,
                         ForwardIterator result,
                         __true_type) {//_true_type说明是POD类型
  return copy(first, last, result);//调用STL算法copy()
}
 
template <class InputIterator, class ForwardIterator>
ForwardIterator 
__uninitialized_copy_aux(InputIterator first, InputIterator last,
                         ForwardIterator result,
                         __false_type) {//_false_type说明是non-POD类型,要一个一个的构建,无法批量进行
  ForwardIterator cur = result;
  __STL_TRY {
    for ( ; first != last; ++first, ++cur)//一个一个的构建
      construct(&*cur, *first);
    return cur;
  }
  __STL_UNWIND(destroy(result, cur));
}

从这个角度来看,如果想让某些函数运行的更快,需要定义__type_traits的特化版本来告诉编译器才行。这样定义的类是更有效率的。

class AAA {};
template <>
struct __type_traits<AAA> {                     //定义AAA之后,同时定义这个。
    typedef __true_type has_trivial_default_constructor;
    typedef __true_type has_trivial_copy_constructor;
    typedef __true_type has_trivial_assignment_constructor;
    typedef __true_type has_trivial_destructor;
    typedef __true_type is_POD_type;
};

但C++11已经有对应函数来确定你的类是否包含这些信息:

is_constructible
is_trivially_constructible
is_nothrow_constructible
 
checks if a type has a constructor for specific arguments 
(class template)
is_default_constructible
is_trivially_default_constructible
is_nothrow_default_constructible
 
checks if a type has a default constructor 
(class template)
is_copy_constructible
is_trivially_copy_constructible
is_nothrow_copy_constructible
  
//更多可以参考:cppreference.com 中的type_traits

这些类的实现,应该是利用编译器的能力来实现的,此时定义类AAA的时候就不用同时定义traits的特化版本了。

std::is_trivially_default_constructible<AAA>     //true_type ,可以利用这个来实现函数调用,而不用if来区分;
is_trivially_default_constructible<AAA> ::value  //true or false;

总结一句,traits通过类模板特化等方式,通过编译器获取类型信息。要获取的信息可以封装在类内部,并定义对应的static value,或者对应的typedef。

相关文章

  • C++ traits使用

    traits一般是利用编译器的能力来获取一些信息。采取的实现方案是模板与模板特化。 实现细节:模板类与static...

  • C++ Traits

    STL 偏特化设计 迭代器型别 value_type,指的是迭代器所指的对象的型别typedef T value_...

  • C++ Traits和Policy演示累加器和累乘器

    仿照 C++ Templates 《Traits and Policy Classes》这一章,改进了一下,造了一...

  • C++:a template declaration is no

    我写了一段代码,想要测试一下C++ 11的一些type traits。 错误提示告诉我我不能够再这里使用templ...

  • C++11 模板元编程 - Traits in TLP

    C++标准库STL中的type_traits文件中,已经有了比较全面的C++ trait组件,可以用来对代码做各种...

  • C++ STL之Traits

    iterator模式定义如下:提供一种方法,使之能够依序寻访某个聚合物所含的各个元素,而又无需暴露该聚合物的内部表...

  • C++ STL之Traits

    https://www.jianshu.com/p/c6e566071fdf

  • Traits (formerly Units)(译)

    这篇文档将会介绍什么是Traits,为什么它们是一个好用的概念,以及怎样使用和创建它们。 Traits可以帮助交互...

  • C++ STL与泛型编程-第五篇 (Boolan)

    C++ STL与泛型编程-第五篇 (Boolan) 本章内容:1 tuple用例2 Type traits3 Ty...

  • C++ is_base_of

    在理解type_traits类型判断的时候,看到网上关于is_base_of的源码,自己C++水平有限,特别是模版...

网友评论

      本文标题:C++ traits使用

      本文链接:https://www.haomeiwen.com/subject/sgwtwftx.html