MyTinySTL阅读笔记---仿函数和配接器

本文详细介绍了STL中的仿函数,包括为何不使用函数指针的原因,以及仿函数按照参数个数和功能的分类。内容涵盖了一元和二元仿函数的基类,算术、关系和逻辑运算的仿函数实现,并展示了MyTinySTL中的仿函数实现,如哈希函数对象。此外,还提及了配接器在修改接口中的应用。
摘要由CSDN通过智能技术生成

仿函数

所谓仿函数也就是函数对象, 以前是这样称呼它的, 只是一直沿用至今了。
仿函数就是一种具有函数特质的对象.。
可以将部分操作由用户自己来定义然后传入自定义的函数名就可以被调用。

为什么不用函数指针

  • 函数指针不能满足STL的抽象性
  • 函数指针不能与STL的其他组件搭配, 不够灵活
  • 仿函数具有可配接性, 可以满足traits编程, 也是能在编译期间就能完成, 不会有运行时的开销

根据参数个数分类

一元仿函数

一元仿函数基类:

template <class Arg, class Result>
struct unary_function {
    typedef Arg argument_type;	// 参数类型别名
    typedef Result result_type;	// 返回值类型别名
};

二元仿函数

二元仿函数基类:

template <class Arg1, class Arg2, class Result>
struct binary_function {
    typedef Arg1 first_argument_type;	// 参数类型别名
    typedef Arg2 second_argument_type;	// 参数类型别名
    typedef Result result_type;	// 返回值类型别名
}; 

根据功能分类

算术运算

如加法:

template <class T>
struct plus : public binary_function<T, T, T> {
    T operator()(const T& x, const T& y) const { return x + y; }
};

关系运算

如等于:

template <class T>
struct equal_to : public binary_function<T, T, bool> {
    bool operator()(const T& x, const T& y) const { return x == y; }
};

逻辑运算

如与:

template <class T>
struct logical_and : public binary_function<T, T, bool> {
    bool operator()(const T& x, const T& y) const { return x && y; }
};

正同,选择,投射

  • 正同 : 任何数值调用该函数都不会有改变
template <class T>
struct identity : public unary_function<T, T> {
  const T& operator()(const T& x) const { return x; }
};
  • 选择 : 接受一个pair类型, 并且返回第一个元素或者第二个元素
// 选择第一个元素
template <class Pair>
struct select1st : public unary_function<Pair, typename Pair::first_type> {
  const typename Pair::first_type& operator()(const Pair& x) const
  {
    return x.first;
  }
};
// 选择第二个元素
template <class Pair>
struct select2nd : public unary_function<Pair, typename Pair::second_type> {
  const typename Pair::second_type& operator()(const Pair& x) const
  {
    return x.second;
  }
};
  • 投影 : 接受一个pair类型, 忽略第二个元素返回第一个元素或者忽略第一个元素返回第二个元素
// 忽略第二个元素返回第一个元素
template <class Arg1, class Arg2>
struct project1st : public binary_function<Arg1, Arg2, Arg1> {
  Arg1 operator()(const Arg1& x, const Arg2&) const { return x; }
};
// 忽略第一个元素返回第二个元素
template <class Arg1, class Arg2>
struct project2nd : public binary_function<Arg1, Arg2, Arg2> {
  Arg2 operator()(const Arg1&, const Arg2& y) const { return y; }
};

MyTinySTL仿函数

涉及到的文件functional.h。
代码和上面介绍的一模一样,我就不贴了。

文件中还有个哈希函数对象,对于整型类型可以看到都是返回原值。

template <class Key>
struct hash {};

/*! 哈希函数对象 针对指针的偏特化版本 返回指针的值 */
template <class T>
struct hash<T*>
{
	size_t operator()(T* p) const noexcept
	{
		return reinterpret_cast<size_t>(p);
	}
};

/*! 哈希函数对象 对于整型类型,只是返回原值 */
#define MYSTL_TRIVIAL_HASH_FCN(Type)         \
template <> struct hash<Type>                \
{                                            \
  size_t operator()(Type val) const noexcept \
  { return static_cast<size_t>(val); }       \
};

MYSTL_TRIVIAL_HASH_FCN(bool)

MYSTL_TRIVIAL_HASH_FCN(char)

MYSTL_TRIVIAL_HASH_FCN(signed char)

MYSTL_TRIVIAL_HASH_FCN(unsigned char)

MYSTL_TRIVIAL_HASH_FCN(wchar_t)

MYSTL_TRIVIAL_HASH_FCN(char16_t)

MYSTL_TRIVIAL_HASH_FCN(char32_t)

MYSTL_TRIVIAL_HASH_FCN(short)

MYSTL_TRIVIAL_HASH_FCN(unsigned short)

MYSTL_TRIVIAL_HASH_FCN(int)

MYSTL_TRIVIAL_HASH_FCN(unsigned int)

MYSTL_TRIVIAL_HASH_FCN(long)

MYSTL_TRIVIAL_HASH_FCN(unsigned long)

MYSTL_TRIVIAL_HASH_FCN(long long)

MYSTL_TRIVIAL_HASH_FCN(unsigned long long)

#undef MYSTL_TRIVIAL_HASH_FCN

对于浮点类型是逐位哈希。

/**
 * @brief 逐位哈希
 * @param[in] first 数据地址
 * @param[in] count 数据位数
 */
inline size_t bitwise_hash(const unsigned char* first, size_t count)
{
#if (_MSC_VER && _WIN64) || ((__GNUC__ || __clang__) &&__SIZEOF_POINTER__ == 8)
	const size_t fnv_offset = 14695981039346656037ull;
	const size_t fnv_prime = 1099511628211ull;
#else
	const size_t fnv_offset = 2166136261u;
	const size_t fnv_prime = 16777619u;
#endif
	size_t result = fnv_offset;
	for (size_t i = 0; i < count; ++i)
	{
		result ^= (size_t)first[i];
		result *= fnv_prime;
	}
	return result;
}

/*! 哈希函数对象 对于浮点数,逐位哈希 */
template <>
struct hash<float>
{
	size_t operator()(const float& val)
	{
		return val == 0.0f ? 0 : bitwise_hash((const unsigned char*)&val, sizeof(float));
	}
};

/*! 哈希函数对象 对于浮点数,逐位哈希 */
template <>
struct hash<double>
{
	size_t operator()(const double& val)
	{
		return val == 0.0f ? 0 : bitwise_hash((const unsigned char*)&val, sizeof(double));
	}
};

/*! 哈希函数对象 对于浮点数,逐位哈希 */
template <>
struct hash<long double>
{
	size_t operator()(const long double& val)
	{
		return val == 0.0f ? 0 : bitwise_hash((const unsigned char*)&val, sizeof(long double));
	}
};

配接器

主要用来修改接口。就像转接口一样, 将一个对class封装变成了另外一个功能的class。

STL 主要提供如下三种配接器:

  1. 改变仿函数(functors)接口,称之为 function adapter
  2. 改变容器(containers)接口,称之位 container adapter
  3. 改变迭代器(iterators)接口者,称之为 iterator adapter
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值