跳转到内容

C++/functional

维基教科书,自由的教学读本
< C++

functional是b:C++标准程式库中的一个b:头文件,定义了C++ STL标准中的基础性的算法(均为函数模板)。

命名空间placeholders[编辑]

定义了用作 std::bind 表达式中的未绑定实参的占位符常量:_1, _2, _3, _4, ...

[编辑]

function类模板[编辑]

包装具有指定的函数调用签名的可调用对象类型

mem_fn函数模板[编辑]

从成员指针创建出函数对象。对数据成员指针也适用。与bind函数模板的区别是,mem_fn只关注、包装了类成员指针,而bind需要指明参数。例如:

#include <functional>
#include <iostream>
 
struct Foo {
    void display_greeting() {
        std::cout << "Hello, world.\n";
    }
    void display_number(int i) {
        std::cout << "number: " << i << '\n';
    }
    int data = 7;
};
 
int main() {
    Foo f;
 
    auto greet = std::mem_fn(&Foo::display_greeting);
    greet(&f);
 
    auto print_num = std::mem_fn(&Foo::display_number);
    print_num(&f, 42);
 
    auto access_data = std::mem_fn(&Foo::data);
    std::cout << "data: " << access_data(&f) << '\n';
}

bad_function_call类[编辑]

调用空的 std::function 时抛出的异常

is_bind_expression类模板[编辑]

若类型T是调用 std::bind 产生的类型,则此模板从 std::true_type 导出。对于任何其他类型,此模板从 std::false_type 导出。

is_placeholder类模板[编辑]

若类型T是标准占位符_1 、 _2 、 _3、……的类型,则此模板分别派生自std::integral_constant<int,1> 、 std::integral_constant<int,2> 、 std::integral_constant<int,3> 等。

若类型T不是标准占位符类型,则此模板派生自std::integral_constant<int,0>。

实际上,bind函数模板用is_placeholder来确定是第几个参数的占位符。

reference_wrapper类模板[编辑]

可复制构造 (CopyConstructible) 且可复制赋值 (CopyAssignable) 的引用包装器(引用的容器)。实现时,有一个数据类型的指针成员变量,在需要数据类型引用时返回相应的解引用。

hash类模板[编辑]

template< class Key > struct hash;

允许的特化模板类是“函数对象”,实现了哈希函数。即定义了operator() const,接受一个Key类型的参数,返回size_t的哈希结果值。对于一个类型,相同值具有相同的哈希结果,不同值具有不同的哈希结果(受限于size_t的值域)。该类别用于4种无序关联容器,不适用于加密算法。

各种基础类型、大多数标准库的类型(如std::string<、code>)已经特化实现了hash类模板。但对于std::pair,需要用boost::hash

对自定义的类实现hash功能,有两种办法:

#include <cstddef>
#include <functional>
#include <iomanip>
#include <iostream>
#include <string>
#include <unordered_set>
 
struct S
{
    std::string first_name;
    std::string last_name;
    bool operator==(const S&) const = default; // since C++20
};
 
// Before C++20.
// bool operator==(const S& lhs, const S& rhs)
// {
//     return lhs.first_name == rhs.first_name && lhs.last_name == rhs.last_name;
// }
 
// Custom hash can be a standalone function object.
struct MyHash
{
    std::size_t operator()(const S& s) const noexcept
    {
        std::size_t h1 = std::hash<std::string>{}(s.first_name);
        std::size_t h2 = std::hash<std::string>{}(s.last_name);
        return h1 ^ (h2 << 1); // or use boost::hash_combine
    }
};
 
// Custom specialization of std::hash can be injected in namespace std.
template<>
struct std::hash<S>
{
    std::size_t operator()(const S& s) const noexcept
    {
        std::size_t h1 = std::hash<std::string>{}(s.first_name);
        std::size_t h2 = std::hash<std::string>{}(s.last_name);
        return h1 ^ (h2 << 1); 
        // or use boost::hash_combine:
        // std::size_t seed = 0;
        // boost::hash_combine(seed, s.first_name);
        // boost::hash_combine(seed, s.last_name);
    }
};

//推荐用法
	template <class T> class A {
		T x;
	public:
		A(T x) : x(x) {}
		bool operator==(A const& b) { return x == b.x; }            //可定义为成员或普通函数
		//std::size_t hash_value() { return boost::hash<T>()(x); }  //error不能定义为类成员函数
		friend std::size_t hash_value(const A<T>& a) { return boost::hash<T>{}(a.x); }
	};

//备选用法-编译器若不支持模板friend(不支持 ADL 的编译器)
	// (不能声明为friend hash_value)hash_value需要在boost命名空间中定义
	template <class T> class A1 {
		T x;
	public:
		A1(T x) : x(x) {}
		bool operator==(A1 const& b) { return x == b.x; }//可定义为成员或普通函数
		std::size_t hash() const {return boost::hash<T>{}(x); }
	};

template <class T>std::size_t hash_value(A1<T> x){return x.hash();}
 
int main()
{
    std::string str = "Meet the new boss...";
    std::size_t str_hash = std::hash<std::string>{}(str);
    std::cout << "hash(" << std::quoted(str) << ") =\t" << str_hash << '\n';
 
    S obj = {"Hubert", "Farnsworth"};
    // Using the standalone function object.
    std::cout << "hash(" << std::quoted(obj.first_name) << ", "
              << std::quoted(obj.last_name) << ") =\t"
              << MyHash{}(obj) << " (using MyHash) or\n\t\t\t\t"
              << std::hash<S>{}(obj) << " (using injected specialization)\n";
 
    // Custom hash makes it possible to use custom types in unordered containers.
    // The example will use the injected std::hash<S> specialization above,
    // to use MyHash instead, pass it as a second template argument.
    std::unordered_set<S> names = {obj, {"Bender", "Rodriguez"}, {"Turanga", "Leela"}};
    for (auto const& s: names)
        std::cout << std::quoted(s.first_name) << ' '
                  << std::quoted(s.last_name) << '\n';
}

函数[编辑]

bind函数模板[编辑]

绑定一或多个实参到函数对象。参见示例一节。

ref与cref函数模板[编辑]

创建具有从其实参推导的类型的 std::reference_wrapper

invoke函数模板[编辑]

(C++17)以给定实参调用任意可调用 (Callable) 对象

函数对象[编辑]

算术运算[编辑]

  • plus类模板
  • minus类模板
  • multiplies类模板
  • divides类模板
  • modulus类模板
  • negate类模板

比较[编辑]

  • equal_to类模板
  • not_equal_to类模板
  • greater类模板
  • less类模板
  • greater_equal类模板
  • less_equal类模板

C++20概念制约的比较[编辑]

  • ranges::equal_to类
  • ranges::not_equal_to类
  • ranges::greater类
  • ranges::less类
  • ranges::greater_equal类
  • ranges::less_equal类

逻辑运算[编辑]

  • logical_and类模板
  • logical_or类模板
  • logical_not类模板

位运算[编辑]

  • bit_and类模板
  • bit_or类模板
  • bit_xor类模板
  • bit_not类模板

取反器[编辑]

not_fn函数模板:(C++17)创建返回其保有的函数对象的结果之补的函数对象

搜索器[编辑]

  • default_searcher类模板:(C++17)标准 C++ 库搜索算法实现
  • boyer_moore_searcher类模板:(C++17)Boyer-Moore 搜索算法实现
  • boyer_moore_horspool_searcher类模板:(C++17)Boyer-Moore-Horspool 搜索算法实现

示例[编辑]

#include <functional>
#include <iostream>
using namespace std;

std::function< int(int)> Functional;

// 普通函数
int TestFunc(int a)
{
	return a;
}

// Lambda表达式
auto lambda = [](int a)->int { return a; };

// 仿函数(functor)
class Functor
{
public:
	int operator()(int a)
	{
		return a;
	}
};

// 1.类成员函数
// 2.类静态函数
class TestClass
{
public:
	int ClassMember(int a) { return a; }
	static int StaticMember(int a) { return a; }
};

int main()
{
	// 普通函数
	Functional = TestFunc;
	int result = Functional(10);
	cout << "普通函数:" << result << endl;

	// Lambda表达式
	Functional = lambda;
	result = Functional(20);
	cout << "Lambda表达式:" << result << endl;

	// 仿函数
	Functor testFunctor;
	Functional = testFunctor;
	result = Functional(30);
	cout << "仿函数:" << result << endl;

	// 类成员函数
	TestClass testObj;
	Functional = std::bind(&TestClass::ClassMember, testObj, std::placeholders::_1);
	result = Functional(40);
	cout << "类成员函数:" << result << endl;

	// 类静态函数
	Functional = TestClass::StaticMember;
	result = Functional(50);
	cout << "类静态函数:" << result << endl;

	return 0;
}