C++ 学习 10 STL 补充

  • 万用hash function
  • Tuple
  • type traits
  • move

万用hash function

使用unordered container时(unordered set/multiset map/multimap)
如果是自定义类型需要指定hash function。
有两种指定方式
1. functor
2. function

//1.
#inclcude 
class Customer {
}
class CustomerHash{
public:
std::size_t operator()(const Customer& c) const {
    return ...;
}
};

unordered_set custset;

//2.
size_t customer_hash_func(const Customer& c) {
    return ...;
}
unordered_setconst Customer&)> custset(20,customer_hash_func)

在C++2.0 中提供了一个万用hash function:可以用来代替上述自定义hash

class CustomerHash {
public:
    std::size_t operator()(const Customer& c) const {
    return hash_val(c.fname, c.lname, c.no);
}
};

//1.
template<typename... types>//不定参模板
inline size_t hash_val(const Types&... args) {
    size_t seed=0;
    hash_val(seed,args...);
    return seed;
}
//2.
template<typename T, typename... Types>
inline void hash_val(size_t& seed, const T& val,const Types&... args) {
    hash_combine(seed,val);
    hash_val(seed,args);
}
//3.结束函数
template<typename T>
inline void hash_val(size_t& seed, const T& val)
{
    hash_combine(seed,val);
}

template<typename T>
inline void hash_combine(size_t& seed, const T&val){
    seed^=std::hash()(val) +0x9e3779b9 + (seed<<6) +(seed>>2);//0x9e3779b9 黄金分割率
}

tuple

tuple是一个固定大小的不同类型值的集合
头文件:

#include

//构造一个tuple
tuple<const char*, int>tp = make_tuple(sendPack,nSendSize); 
//用std::tie,它会创建一个元组的左值引用。
auto tp = return std::tie(1, "aa", 2);
const char* data = tp.get<0>(); //获取第一个值
int len = tp.get<1>(); //获取第二个值
//还有一种方法也可以获取元组的值,通过std::tie解包tuple
int x,y;
string a;
std::tie(x,a,y) = tp; 
//解包时,我们如果只想解某个位置的值时,可以用std::ignore占位符来表示不解某个位置的值。比如我们只想解第三个值时:
std::tie(std::ignore,std::ignore,y) = tp; //只解第三个值了
//还有一个创建右值的引用元组方法:forward_as_tuple。
std::map<int, std::string> m;
m.emplace(std::forward_as_tuple(10, std::string(20, 'a')));
//它实际上创建了一个类似于std::tuple类型的tuple。
//我们还可以通过tuple_cat连接多个tupe
std::tuple<int, std::string, float> t1(10, "Test", 
3.14);
int n = 7;
auto t2 = std::tuple_cat(t1, std::make_pair("Foo", 
"bar"), t1, std::tie(n));
//通过std::tuple_element获取元素类型。
std::tuple_element<0,Tuple>::type first = std::get<0> 
(mytuple);
std::tuple_element<1,Tuple>::type second = std::get<1> 
(mytuple);
//获取tuple中元素的个数:
int size = std::tuple_size<decltype(t))>::value;
//遍历tuple
template<class Tuple, std::size_t N>
struct TuplePrinter {
    static void print(const Tuple& t)
    {
        TuplePrinter1>::print(t);
        std::cout << ", " << std::get1>(t);
    }
};

template<class Tuple>
struct TuplePrinter1>{
    static void print(const Tuple& t)
    {
        std::cout << std::get<0>(t);
    }
};

template<class... Args>
void PrintTuple(const std::tuple& t)
{
    std::cout << "(";
    TuplePrinter<decltype(t), sizeof...(Args)>::print(t);
    std::cout << ")\n";
}

实现:

template<typename... Values> class tuple;
template<> class tuple<> {};

template<typename Head, typename... Tail>
class tuple:private tuple
{
    typedef tuple inherited;
public:
    tuple(){}
    tuple(Head v, Tail...vtail):m_head(head), inherited(vtail...) {}
    typename Head::type head() {return m_head;}
    inherited& tail() {return *this;}
protected:
    Head m_head;
};
//example
tuple<int, float, string> t(41, 6.3, "nico");
t.head();//得到41
t.tail();// 得到inherited 类型tail
t.tail().head();// 得到6.3

C++ 学习 10 STL 补充_第1张图片

参考:http://blog.csdn.net/fjb2080/article/details/15809097
http://www.cplusplus.com/reference/tuple/

type traits

萃取类型信息:

//GNU 2.9
template type>
sturct __type_traits{
    typedef __true_type this_dummy_memeber_must_be_first;
    type __false_type has_trivial_default_constructor//拥有不重要的构造函数--〉 faslse
    typedef __false_type has_trivial_copy_constructor;
    typedef __false_type has_trivial_assignment_operator;
    typedef __false_type has_trivial_destructor;
    typedef __false_type is_POD_type;//plain old data   
};
template<> struct __type_traits {
    typedef __true_type has_trivial_default_constructor;
typedef __true_type has_trivial_copy_constructor;
    typedef __true_type has_trivial_assignment_operator;
    typedef __true_type has_trivial_destructor;
    typedef __true_type is_POD_type;//plain old data    
};
...//same with double, char...

c++ 11 之后不需要自己再写专门的自定义类型特化版本 type_traits. 分成了不同的模板类型来萃取不同类型信息。

is_abstract
is_const
is_empty
is_literal_type
is_pod
is_polymorphic
is_signed
is_standard_layout
is_trivial
is_unsigned
is_volatile
is_array
is_class
is_enum
is_floating_point
is_function
is_integral
is_lvalue_reference
is_member_function_pointer
is_member_object_pointer
is_reference
is_union
is_void
...

实现 is_void:

//remove const
template<typename _Tp>
struct remove_const {typedef _Tp type;};
//const 特化来找出含有const的参数
template<typename _Tp>
struct remove_const<_Tp const>{typedef _Tp type};
//remove volatile
template<typename _Tp>
struct remove_volatile{typedef _Tp type};
template<typename _Tp>
struct remove_volatile<_Tp volatile> {typedef _Tp type};
//remove cv
template<typename _Tp>
struct remove_cv{
    typedef typename
        remove_const<typename remove_volatile<_Tp>::type>::type   type;
};
template <typename>
struct is_void_helper:public false_type{};
//void 特化版
template<>
struct __is_void_helper<void>:public true_type{};
//is_void
template<typename _Tp>
struct is_void:public __is_void_helper<typename remove_cv<_Tp>::type>::type {};

其他 is_integral实现类似。
但是is_class is_union is_enum is_polymorphic 需要编译器配合才能实现。

move

参考:
http://blog.csdn.net/fjb2080/article/details/14164549
http://blog.csdn.net/liyongofdm/article/details/7667942
decltype:
返回值 decltype(表达式)这个可也用来决定表达式的类型,就像Bjarne暗示的一样,如果我们需要去初始化某种类型的变量,auto是最简单的选择,但是如果我们所需的类型不是一个变量,例如返回值这时我们可也试一下decltype。

template <class U, class V>  
void Somefunction(U u, V v)  
{  
    result = u*v;//now what type would be the result???  
    decltype(u*v) result = u*v;//Hmm .... we got what we want  
}  

1.如果这个表达式是个函数,decltype 给出的类型为函数返回值的类型。

decltype(add(5,6)) var = 5;

2.如果表达式是一个左值类型,那么 decltype 给出的类型为表达式左值引用类型。

struct M { double x; };  

double pi = 3.14;  
const M* m = new M();  
decltype( (m->x) ) piRef = pi;  

    // Note: Due to the inner bracets the inner statement is evaluated as expression,  
    // rather than member 'x' and as type of x is double and as this is lvale  
    // the return of declspec is double& and as 'm' is a const pointer   
    // the return is actually const double&.  
    // So the type of piRef is const double&  

3.非常重要的标记一下,decltype 不会执行表达式而auto会,他仅仅推论一下表达式的类型。

int foo(){}  
decltype( foo() ) x; // x is an int and note that   
                     // foo() is not actually called at runtime  

推导规则:
1. 如果e是一个没有带括号的标记符表达式或者类成员访问表达式,那么的decltype(e)就是e所命名的实体的类型。此外,如果e是一个被重载的函数,则会导致编译错误。
2. 否则 ,假设e的类型是T,如果e是一个将亡值,那么decltype(e)为T&&
3. 否则,假设e的类型是T,如果e是一个左值,那么decltype(e)为T&。
4. 否则,假设e的类型是T,则decltype(e)为T。
参考:
http://blog.csdn.net/yshe_xun/article/details/7315135
http://www.cnblogs.com/QG-whz/p/4952980.html

你可能感兴趣的:(语言学习,c语言)