使用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是一个固定大小的不同类型值的集合
头文件:
#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
参考:http://blog.csdn.net/fjb2080/article/details/15809097
http://www.cplusplus.com/reference/tuple/
萃取类型信息:
//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 需要编译器配合才能实现。
参考:
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