C++11新特性应用--实现延时求值(std::function和std::bind)

说是延时求值,注意还是想搞一搞std::function和std::bind。

之前博客《C++11新特性之std::function》注意是std::function怎样实现回调函数。

如今就算是补充吧,再把std::bind进行讨论讨论。

何为Callable Objects?

就可以调用对象,比方函数指针、仿函数、类成员函数指针等都可称为可调用对象。

对象包装器

Function wrapper

Class that can wrap any kind of callable element (such as functions and function objects) into a copyable object, and whose type depends solely on its call signature (and not on the callable element type itself).

An object of a function class instantiation can wrap any of the following kinds of callable objects: a function, a function pointer, a pointer to member, or any kind of function object (i.e., an object whose class defines operator(), including closures).

A decay copy of the wrapped callable object is stored internally by the object, which becomes the function’s target. The specific type of this target callable object is not needed in order to instantiate the function wrapper class; only its call signature.

以下用一段代码:

#include<iostream>
#include<functional>

//普通函数
void func(void)
{
    std::cout << "1" << std::endl;
}

//类的成员函数
class A
{
public:
    static int A_func(int a)
    {
        std::cout << "2" << "(" << a << ")" << std::endl;
        return a;
    }
};

//仿函数
class B
{
public:
    int operator()(int a)
    {
        std::cout << "2" << "(" << a << ")" << std::endl;
        return a;
    }
};

int main()
{
    std::function<void(void)> fun1 = func;
    fun1();

    std::function<int(int)> fun2 = A::A_func;
    std::cout << fun2(123) << std::endl;

    B b;
    fun2 = b;
    std::cout << fun2(123) << std::endl;

    return 0;
}
//输出:
1
2(123)
123
2(123)
123

接下来std::function用于回调就不浪费篇幅了,接下来注意分析std::bind。

何为std::bind?

字面意思。绑定器。

simple

template

#include <iostream>     // std::cout
#include <functional>   // std::bind

// a function: (also works with function object: std::divides<double> my_divide;)
double my_divide(double x, double y) { return x / y; }

struct MyPair {
    double a, b;
    double multiply() { return a*b; }
};

int main() {
    using namespace std::placeholders;    // adds visibility of _1, _2, _3,...

    // binding functions:
    auto fn_five = std::bind(my_divide, 10, 2);              // returns 10/2
    std::cout << fn_five() << ‘\n‘;                          // 5

    auto fn_half = std::bind(my_divide, _1, 2);              // returns x/2
    std::cout << fn_half(10) << ‘\n‘;                        // 5

    auto fn_invert = std::bind(my_divide, _2, _1);            // returns y/x
    std::cout << fn_invert(10, 2) << ‘\n‘;                    // 0.2

    auto fn_rounding = std::bind<int>(my_divide, _1, _2);   // returns int(x/y)
    std::cout << fn_rounding(10, 3) << ‘\n‘;                  // 3

    MyPair ten_two{ 10,2 };

    // binding members:

    // returns x.multiply()
    auto bound_member_fn = std::bind(&MyPair::multiply, _1);               

    std::cout << bound_member_fn(ten_two) << ‘\n‘;           // 20

    // returns ten_two.a
    auto bound_member_data = std::bind(&MyPair::a, ten_two);
    std::cout << bound_member_data() << ‘\n‘;                // 10

    return 0;
}

_ 1中的 _ 表示的是占位符,由using namespace std::placeholders; 提供。详细的话找机会再研究。

主要看看上面的代码。bind的几种使用方式。

能够看到。能够绑定所有參数,也能够绑定部分參数。

你可能已经感到bind的威力了吧,那不是重点。与function的结合才是重要的:

//#include <iostream>     // std::cout
//#include <functional>   // std::bind
//
//// a function: (also works with function object: std::divides<double> my_divide;)
//double my_divide(double x, double y) { return x / y; }
//
//struct MyPair {
//  double a, b;
//  double multiply() { return a*b; }
//};
//
//int main() {
//  using namespace std::placeholders;    // adds visibility of _1, _2, _3,...
//
//                                        // binding functions:
//  auto fn_five = std::bind(my_divide, 10, 2);               // returns 10/2
//  std::cout << fn_five() << ‘\n‘;                          // 5
//
//  auto fn_half = std::bind(my_divide, _1, 2);               // returns x/2
//  std::cout << fn_half(10) << ‘\n‘;                        // 5
//
//  auto fn_invert = std::bind(my_divide, _2, _1);            // returns y/x
//  std::cout << fn_invert(10, 2) << ‘\n‘;                    // 0.2
//
//  auto fn_rounding = std::bind<int>(my_divide, _1, _2);     // returns int(x/y)
//  std::cout << fn_rounding(10, 3) << ‘\n‘;                  // 3
//
//  MyPair ten_two{ 10,2 };
//
//  // binding members:
//  auto bound_member_fn = std::bind(&MyPair::multiply, _1); // returns x.multiply()
//  std::cout << bound_member_fn(ten_two) << ‘\n‘;           // 20
//
//  auto bound_member_data = std::bind(&MyPair::a, ten_two); // returns ten_two.a
//  std::cout << bound_member_data() << ‘\n‘;                // 10
//
//  return 0;
//}

#include<iostream>
#include<functional>

class A {
public:
    int i_ = 0;
    void output(int x, int y)
    {
        std::cout << x << " " << y << std::endl;
    }
};

int main()
{
    A a;
    std::function<void(int, int)> func1 = std::bind(&A::output, &a, std::placeholders::_1,
        std::placeholders::_2);
    func1(1, 2);

    std::function<int&(void)> func2 = std::bind(&A::i_, &a);
    func2() = 888;

    std::cout << a.i_ << std::endl;
    return 0;
}

//输出:
1 2
888
时间: 2024-11-02 11:27:18

C++11新特性应用--实现延时求值(std::function和std::bind)的相关文章

C++11新特性(1) 右值引用

在C++中,左值(lvalue)是可以获取其地址的一个量.由于经常出现在赋值语句的左边,因此称之为左值.例如一个有名称的变量. 例如: int a=10; //a就是一个左值. 传统的C++引用,都是左值引用.例如:int &ra=a;将ra关联到a.这就是左值引用. C++11,新增了右值引用的概念.用&&代表右值引用. 首先我们来看一下什么叫做右值.可以说所有不是左值的量都是右值.例如文本,临时对象或者临时值(都是不能获取地址的量). 右值引用,就是一个对右值的引用.特别地,这

C++11新特性之 rvalue Reference(右值引用)

右值引用可以使我们区分表达式的左值和右值. C++11引入了右值引用的概念,使得我们把引用与右值进行绑定.使用两个"取地址符号": int&& rvalue_ref = 99; 需要注意的是,只有左值可以付给引用,如: int& ref = 9; 我们会得到这样的错误: "invalid initialization of non-const reference of type int& from an rvalue of type int&q

C++:C++11新特性超详细版(1)

前言: 虽然目前没有编译器能够完全实现C++11,但这并不意味着我们不需要了解,学习它.深入学习C++11,你会发现这根本就是一门新的语言,它解决了c++98中许多遗留下来的问题.早晚会有一天,C++11便会普及大部分编译器.因此,提早做些准备也是应该的. 在此我想做一个关于C++11的专题,将C++11的新特性进行一一讲解,以通俗易懂的语言及例子帮助读者入门C++11.本文便是C++11新特性超详细版系列文章的第一篇, 即C++:[C++11]新特性超详细版(1). 不过我要强调的是,这些文章

C++11 新特性之 tuple

我们在C++中都用过pair.pair是一种模板类型,其中包含两个数据值,两个数据的类型可以不同.pair可以使用make_pair构造 pair<int, string> p = make_pair(1, "a1"); 如果传入的参数为多个,那么就需要嵌套pair,如下代码 #include <iostream> #include <map> using namespace std; int main() { //<int, string,

C++11 新特性之 变长参数模板

template <typename ... ARGS> void fun(ARGS ... args) 首先明确几个概念 1,模板参数包(template parameter pack):它指模板参数位置上的变长参数,例如上面例子中的ARGS 2,函数参数包(function parameter pack):它指函数参数位置上的变长参数,例如上面例子中的args 一般情况下 参数包必须在最后面,例如: template <typename T, typename ... Args>

【C++11】30分钟了解C++11新特性

作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 什么是C++11 C++11是曾经被叫做C++0x,是对目前C++语言的扩展和修正,C++11不仅包含核心语言的新机能,而且扩展了C++的标准程序库(STL),并入了大部分的C++ Technical Report 1(TR1)程序库(数学的特殊函数除外). C++11包括大量的新特性:包括lambda表达式,类型推导关键字auto.decl

[C++11新特性]第二篇

0.可变数量参数,可变函数模版,变长模版类 c++98可变数量参数 #include<cstdio> #include<cstdarg> double SumOfFloat(int count, ...) { va_list ap; double sum=0; va_start(ap,count); for(int i=0;i<count;i++) sum+=va_arg(ap,double); va_end(ap); return sum; } int main() { p

C++11 新特性(5) 统一初始化

在C++11之前,初始化的类型并非总是统一的. 例如以下两个man定义,一个作为结构,一个作为类.两者的初始化是不一样的. #include <iostream> using namespace std; struct manStruct{ string name; int age; }; class manClass { private: string name; int age; public: manClass(string s,int a):name(s),age(a){ } }; i

[cocos2d-x] 一些C++ 11新特性的引入

1.auto关键字的使用 auto关键字原理     在定义变量的时候必须申明类型,c++是强语言类型,在编译阶段需要知道类型,这样的好处是程序效率更高,而动态语言不需要类型申明的需要自推导变量类型.使用了auto是不是c++效率会变慢?完全不是,因为在编译阶段编译器已经帮程序员推导好了变量的类型.前提条件是编译器可以根据当前的程序的状态推导出变量类型.只是编译器更加智能,可能会增加编译工作,但是不会影响运行效率. 实例1:申明普通变量 auto num = 10; 实例2: vector<st