C++函数对象-函数包装器-从成员指针创建出函数对象(std::mem_fn)

任何定义了函数调用操作符的对象都是函数对象。C++ 支持创建、操作新的函数对象,同时也提供了许多内置的函数对象。

函数包装器

std::function 提供存储任意类型函数对象的支持。

从成员指针创建出函数对象

std::mem_fn

template< class M, class T >
/*unspecified*/ mem_fn(M T::* pm);

(C++11 起)
(C++17 前)

template< class M, class T >
/*unspecified*/ mem_fn(M T::* pm) noexcept;

(C++17 起)

函数模板 std::mem_fn 生成指向成员指针的包装对象,它可以存储、复制及调用指向成员指针。到对象的引用和指针(含智能指针)可在调用 std::mem_fn 时使用。

参数

pm - 指向被包装成员的指针

返回值

std::mem_fn 返回未指定类型的调用包装,该类型拥有下列成员:

std::mem_fn 返回类型

成员类型

类型 定义
result_type(C++17 中弃用) 若 pm 为指向成员函数的指针,则为 pm 的返回类型,对指向成员对象的指针不定义
argument_type(C++17 中弃用) 若 pm 是指向无参数成员函数的指针则为 T* ,可有 cv 限定
first_argument_type(C++17 中弃用) 若 pm 是指向接收一个参数的成员函数的指针则为 T*
second_argument_type(C++17 中弃用) 若 pm 是指向接收一个 T1 类型参数的成员函数的指针则为 T1
(C++20 前)

成员函数

template<class... Args>
/* see below */ operator()(Args&&... args);

fn 为以指向成员的指针 pm 调用std::mem_fn 所返回的调用包装器。则表达式 fn(t, a2, ..., aN) 等价于 INVOKE(pm, t, a2, ..., aN) ,其中 INVOKE 是定义于可调用 (Callable) 的操作。(从而 operator() 的返回类型是std::result_of<decltype(pm)(Args&&...)>::type 。)。

完美转发 args 中的每个参数,如同用 std::forward<Args>(args)... 。

调用示例

#include <functional>
#include <iostream>

struct Foo
{
    void display_greeting()
    {
        std::cout << "Hello, world." << " " << __FUNCTION__ << " " << std::endl;
    }
    void display_number(int i)
    {
        std::cout << "number: " << i << " " << __FUNCTION__ << " " << std::endl;
    }
    int data = 7;
};

int main()
{
    Foo f;

    auto greet = std::mem_fn(&Foo::display_greeting);
    greet(&f);
    std::cout << "typeid(greet).name() " << typeid(greet).name() << std::endl;
    std::cout << "typeid(greet).name() " << typeid(greet).name() << std::endl;

    auto print_num = std::mem_fn(&Foo::display_number);
    print_num(&f, 42);
    std::cout << "typeid(print_num).name() " << typeid(print_num).name() << std::endl;

    auto access_data = std::mem_fn(&Foo::data);
    std::cout << "data: " << access_data(&f) << std::endl;
    std::cout << "typeid(access_data).name() " << typeid(access_data).name() << std::endl;

    return 0;
}

输出

Hello, world. display_greeting
typeid(greet).name() St7_Mem_fnIM3FooFvvEE
typeid(greet).name() St7_Mem_fnIM3FooFvvEE
number: 42 display_number
typeid(print_num).name() St7_Mem_fnIM3FooFviEE
data: 7
typeid(access_data).name() St7_Mem_fnIM3FooiE