rime核心部分代码分析——WeaselServerImpl.cpp文件(十一)

我们已经在之前的文章中对WeaselServer.cpp中的代码及其功能进行了分析,接下来将对WeaselServerImpl.cpp文件进行分析,首先具体的代码如下:

#include "stdafx.h"
#include "WeaselServerImpl.h"
#include <Windows.h>
#include <VersionHelpers.hpp>
#include <resource.h>

namespace weasel {
	class PipeServer : public PipeChannel<DWORD, PipeMessage>
	{
	public:
		using ServerRunner = std::function<void()>;
		using Respond = std::function<void(Msg)>;
		using ServerHandler = std::function<void(PipeMessage, Respond)>;

		PipeServer(std::wstring &&pn_cmd, SECURITY_ATTRIBUTES *s);

	public:
		void Listen(ServerHandler const &handler);
		/* Get a server runner */
		ServerRunner GetServerRunner(ServerHandler const &handler);
	private:
		void _ProcessPipeThread(HANDLE pipe, ServerHandler const &handler);
	};
}


using namespace weasel;

extern CAppModule _Module;

ServerImpl::ServerImpl()
	: m_pRequestHandler(NULL),
	channel(std::make_unique<PipeServer>(GetPipeName(), sa.get_attr()))
{
	m_hUser32Module = GetModuleHandle(_T("user32.dll"));
}

ServerImpl::~ServerImpl()
{
	_Finailize();
}

void ServerImpl::_Finailize()
{
	if (pipeThread != nullptr) {
		pipeThread->interrupt();
	}
	if (IsWindow())
	{
		DestroyWindow();
	}

	m_pRequestHandler->Finalize();
}

LRESULT ServerImpl::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	// not neccessary...
	::SetWindowText(m_hWnd, WEASEL_IPC_WINDOW); 
	return 0;
}

LRESULT ServerImpl::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	Stop();
	return 0;
}

LRESULT ServerImpl::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	bHandled = FALSE;
	return 1;
}

LRESULT ServerImpl::OnQueryEndSystemSession(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	return TRUE;
}

LRESULT ServerImpl::OnEndSystemSession(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	if (m_pRequestHandler)
	{
		m_pRequestHandler->Finalize();
	}
	return 0;
}

LRESULT ServerImpl::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	UINT uID = LOWORD(wParam);
	switch (uID) {
	case ID_WEASELTRAY_ENABLE_ASCII:
		m_pRequestHandler->SetOption(lParam, "ascii_mode", true);
		return 0;
	case ID_WEASELTRAY_DISABLE_ASCII:
		m_pRequestHandler->SetOption(lParam, "ascii_mode", false);
		return 0;
	default:;
	}

	std::map<UINT, CommandHandler>::iterator it = m_MenuHandlers.find(uID);
	if (it == m_MenuHandlers.end())
	{
		bHandled = FALSE;
		return 0;
	}
	it->second();  // execute command
	return 0;
}

DWORD ServerImpl::OnCommand(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam)
{
	BOOL handled = TRUE;
	OnCommand(uMsg, wParam, lParam, handled);
	return handled;
}

int ServerImpl::Start()
{
	std::wstring instanceName = L"(WEASEL)Furandōru-Sukāretto-";
	instanceName += getUsername();
	HANDLE hMutexOneInstance = ::CreateMutex(NULL, FALSE, instanceName.c_str());
	bool areYouOK = (::GetLastError() == ERROR_ALREADY_EXISTS ||
		::GetLastError() == ERROR_ACCESS_DENIED);

	if (areYouOK) {
		return 0; // assure single instance
	}

	HWND hwnd = Create(NULL);

	return (int)hwnd;
}

int ServerImpl::Stop()
{
	_Finailize();
	// quit the server
	::ExitProcess(0);
	return 0;
}



int ServerImpl::Run()
{
	
	// This workaround causes a VC internal error:
	// void PipeServer::Listen(ServerHandler handler);
	// 
	// auto handler = boost::bind(&ServerImpl::HandlePipeMessage, this);
	// auto listener = boost::bind(&PipeServer::Listen, channel.get(), handler);
	//

	auto listener = [this](PipeMessage msg, PipeServer::Respond resp) -> void {
		HandlePipeMessage(msg, resp);
	};
	pipeThread = std::make_unique<boost::thread>([this, &listener]() {
		channel->Listen(listener);
	});

	CMessageLoop theLoop;
	_Module.AddMessageLoop(&theLoop);
	int nRet = theLoop.Run();
	_Module.RemoveMessageLoop();
	return nRet;
}



DWORD ServerImpl::OnEcho(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam)
{
	if (!m_pRequestHandler)
		return 0;
	return m_pRequestHandler->FindSession(lParam);
}

DWORD ServerImpl::OnStartSession(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam)
{
	if (!m_pRequestHandler)
		return 0;
	return m_pRequestHandler->AddSession(
		reinterpret_cast<LPWSTR>(channel->ReceiveBuffer()),
		[this](std::wstring &msg) -> bool {
			*channel << msg;
			return true;
		}
	);
}

DWORD ServerImpl::OnEndSession(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam)
{
	if (!m_pRequestHandler)
		return 0;
	return m_pRequestHandler->RemoveSession(lParam);
}

DWORD ServerImpl::OnKeyEvent(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam)
{
	if (!m_pRequestHandler/* || !m_pSharedMemory*/)
		return 0;

	auto eat = [this](std::wstring &msg) -> bool {
		*channel << msg;
		return true;
	};
	return m_pRequestHandler->ProcessKeyEvent(KeyEvent(wParam), lParam, eat);
}

DWORD ServerImpl::OnShutdownServer(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam)
{
	Stop();
	return 0;
}

DWORD ServerImpl::OnFocusIn(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam)
{
	if (!m_pRequestHandler)
		return 0;
	m_pRequestHandler->FocusIn(wParam, lParam);
	return 0;
}

DWORD ServerImpl::OnFocusOut(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam)
{
	if (!m_pRequestHandler)
		return 0;
	m_pRequestHandler->FocusOut(wParam, lParam);
	return 0;
}

DWORD ServerImpl::OnUpdateInputPosition(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam)
{
	if (!m_pRequestHandler)
		return 0;
	/*
	 * 移位标志 = 1bit == 0
	 * height: 0~127 = 7bit
	 * top:-2048~2047 = 12bit(有符号)
	 * left:-2048~2047 = 12bit(有符号)
	 *
	 * 高解析度下:
	 * 移位标志 = 1bit == 1
	 * height: 0~254 = 7bit(舍弃低1位)
	 * top: -4096~4094 = 12bit(有符号,舍弃低1位)
	 * left: -4096~4094 = 12bit(有符号,舍弃低1位)
	 */
	RECT rc;
	int hi_res = (wParam >> 31) & 0x01;
	rc.left = ((wParam & 0x7ff) - (wParam & 0x800)) << hi_res;
	rc.top = (((wParam >> 12) & 0x7ff) - ((wParam >> 12) & 0x800)) << hi_res;
	const int width = 6;
	int height = ((wParam >> 24) & 0x7f) << hi_res;
	rc.right = rc.left + width;
	rc.bottom = rc.top + height;

	if (IsWindows8Point1OrGreater())
	{
		using PPTLPFPMDPI = BOOL (WINAPI *)(HWND, LPPOINT);
		PPTLPFPMDPI PhysicalToLogicalPointForPerMonitorDPI = (PPTLPFPMDPI)::GetProcAddress(m_hUser32Module, "PhysicalToLogicalPointForPerMonitorDPI");
		POINT lt = { rc.left, rc.top };
		POINT rb = { rc.right, rc.bottom };
		PhysicalToLogicalPointForPerMonitorDPI(NULL, &lt);
		PhysicalToLogicalPointForPerMonitorDPI(NULL, &rb);
		rc = { lt.x, lt.y, rb.x, rb.y };
	}

	m_pRequestHandler->UpdateInputPosition(rc, lParam);
	return 0;
}

DWORD ServerImpl::OnStartMaintenance(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam)
{
	if (m_pRequestHandler)
		m_pRequestHandler->StartMaintenance();
	return 0;
}

DWORD ServerImpl::OnEndMaintenance(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam)
{
	if (m_pRequestHandler)
		m_pRequestHandler->EndMaintenance();
	return 0;
}

DWORD ServerImpl::OnCommitComposition(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam)
{
	if (m_pRequestHandler)
		m_pRequestHandler->CommitComposition(lParam);
	return 0;
}

DWORD ServerImpl::OnClearComposition(WEASEL_IPC_COMMAND uMsg, DWORD wParam, DWORD lParam)
{
	if (m_pRequestHandler)
		m_pRequestHandler->ClearComposition(lParam);
	return 0;
}

#define MAP_PIPE_MSG_HANDLE(__msg, __wParam, __lParam) {\
auto lParam = __lParam;\
auto wParam = __wParam;\
LRESULT _result = 0;\
switch (__msg) {\

#define PIPE_MSG_HANDLE(__msg, __func) \
case __msg:\
	_result = __func(__msg, wParam, lParam);\
	break;\

#define END_MAP_PIPE_MSG_HANDLE(__result) }__result = _result; }

template<typename _Resp>
void ServerImpl::HandlePipeMessage(PipeMessage pipe_msg, _Resp resp)
{
	DWORD result;

	MAP_PIPE_MSG_HANDLE(pipe_msg.Msg, pipe_msg.wParam, pipe_msg.lParam)
		PIPE_MSG_HANDLE(WEASEL_IPC_ECHO, OnEcho)
		PIPE_MSG_HANDLE(WEASEL_IPC_START_SESSION, OnStartSession)
		PIPE_MSG_HANDLE(WEASEL_IPC_END_SESSION, OnEndSession)
		PIPE_MSG_HANDLE(WEASEL_IPC_PROCESS_KEY_EVENT, OnKeyEvent)
		PIPE_MSG_HANDLE(WEASEL_IPC_SHUTDOWN_SERVER, OnShutdownServer)
		PIPE_MSG_HANDLE(WEASEL_IPC_FOCUS_IN, OnFocusIn)
		PIPE_MSG_HANDLE(WEASEL_IPC_FOCUS_OUT, OnFocusOut)
		PIPE_MSG_HANDLE(WEASEL_IPC_UPDATE_INPUT_POS, OnUpdateInputPosition)
		PIPE_MSG_HANDLE(WEASEL_IPC_START_MAINTENANCE, OnStartMaintenance)
		PIPE_MSG_HANDLE(WEASEL_IPC_END_MAINTENANCE, OnEndMaintenance)
		PIPE_MSG_HANDLE(WEASEL_IPC_COMMIT_COMPOSITION, OnCommitComposition)
		PIPE_MSG_HANDLE(WEASEL_IPC_CLEAR_COMPOSITION, OnClearComposition);
		PIPE_MSG_HANDLE(WEASEL_IPC_TRAY_COMMAND, OnCommand);
	END_MAP_PIPE_MSG_HANDLE(result);

	resp(result);
}

PipeServer::PipeServer(std::wstring &&pn_cmd, SECURITY_ATTRIBUTES *s)
	: PipeChannel(std::move(pn_cmd), s)
{}

void PipeServer::Listen(ServerHandler const &handler)
{
	for (;;) {
		HANDLE pipe = INVALID_HANDLE_VALUE;
		try {
			boost::this_thread::interruption_point();
			pipe = _ConnectServerPipe(pname);
			boost::thread th([&handler, pipe, this] {
				_ProcessPipeThread(pipe, handler);
			});
		}
		catch (DWORD ex) {
			_FinalizePipe(pipe);
		}
		boost::this_thread::interruption_point();
	}
}

PipeServer::ServerRunner PipeServer::GetServerRunner(ServerHandler const &handler)
{
	return [&handler, this]() {
		Listen(handler);
	};
}

void PipeServer::_ProcessPipeThread(HANDLE pipe, ServerHandler const &handler)
{
	try {
		for (;;) {
			Res msg;
			_Receive(pipe, &msg, sizeof(msg));
			handler(msg, [this, pipe](Msg resp) {
				_Send(pipe, resp);
			});
		}
	}
	catch (...) {
		_FinalizePipe(pipe);
	}
}



// weasel::Server

Server::Server()
	: m_pImpl(new ServerImpl)
{}

Server::~Server()
{
	if (m_pImpl)
		delete m_pImpl;
}

int Server::Start()
{
	return m_pImpl->Start();
}

int Server::Stop()
{
	return m_pImpl->Stop();
}

int Server::Run()
{
	return m_pImpl->Run();
}

void Server::SetRequestHandler(RequestHandler* pHandler)
{
	m_pImpl->SetRequestHandler(pHandler);
}

void Server::AddMenuHandler(UINT uID, CommandHandler handler)
{
	m_pImpl->AddMenuHandler(uID, handler);
}

HWND Server::GetHWnd()
{
	return m_pImpl->m_hWnd;
}

一、基本概念理解

1.using的具体用法

1、命名空间的使用

一般为了代码的冲突,都会用命名空间。例如,对于Android代码会使用Android作为命名空间。

namespace android;

在code中使用的时候可以用android::加具体的类方法。也可以直接使用using namespace android;

具体的命名空间使用方法不做过多说明。

2、在子类中引用基类的成员

来看下source code:

class T5Base {
public:
    T5Base() :value(55) {}
    virtual ~T5Base() {}
    void test1() { cout << "T5Base test1..." << endl; }
protected:
    int value;
};
 
class T5Derived : private T5Base {
public:
    //using T5Base::test1;
    //using T5Base::value;
    void test2() { cout << "value is " << value << endl; }
};

基类中成员变量value是protected,在private继承之后,对于外界这个值为private,也就是说T5Derived的对象无法使用这个value。

如果想要通过对象使用,需要在public下通过using T5Base::value来引用,这样T5Derived的对象就可以直接使用。

同样的,对于基类中的成员函数test1(),在private继承后变为private,T5Derived的对象同样无法访问,通过using T5Base::test1 就可以使用了。

注意,using只是引用,不参与形参的指定。

3、别名指定

这点就是最开始看到的source code。在C++11中提出了通过using指定别名。

例如上面source code 中:

using value_type = _Ty

以后使用value_type value; 就代表_Ty value;

这个让我们想起了typedef,using 跟typedef有什么区别呢?哪个更好用些呢?

例如:

typedef std::unique_ptr<std::unordered_map<std::string, std::string>> UPtrMapSS;

而C++11中:

using UPtrMapSS = std::unique_ptr<std::unordered_map<std::string, std::string>>;

或许从这个例子中,我们是看不出来明显的好处的(而于我来说,以一个第三者的角度,这个例子也难以说服我一定要用C++11的using)。
再来看下:

typedef void (*FP) (int, const std::string&);

若不是特别熟悉函数指针与typedef的童鞋,我相信第一眼还是很难指出FP其实是一个别名,代表着的是一个函数指针,而指向的这个函数返回类型是void,接受参数是int, const std::string&。那么,让我们换做C++11的写法:

using FP = void (*) (int, const std::string&);

我想,即使第一次读到这样代码,并且知道C++11 using的童鞋也能很容易知道FP是一个别名,using的写法把别名的名字强制分离到了左边,而把别名指向的放在了右边,比较清晰。

而针对这样的例子,我想我可以再补充一个例子:

typedef std::string (Foo::* fooMemFnPtr) (const std::string&);
 
using fooMemFnPtr = std::string (Foo::*) (const std::string&);

从可读性来看,using也是要好于typedef的。

那么,若是从可读性的理由支持using,力度也是稍微不足的。来看第二个理由,那就是举出了一个typedef做不到,而using可以做到的例子:alias templates, 模板别名。

template <typename T>
using Vec = MyVector<T, MyAlloc<T>>;
 
// usage
Vec<int> vec;

这一切都会非常的自然。

那么,若你使用typedef来做这一切:

template <typename T>
typedef MyVector<T, MyAlloc<T>> Vec;
 
// usage
Vec<int> vec;

当你使用编译器编译的时候,将会得到类似:error: a typedef cannot be a template的错误信息。

那么,为什么typedef不可以呢?在 n1449 中提到过这样的话:“we specifically avoid the term “typedef template” and introduce the new syntax involving the pair “using” and “=” to help avoid confusion: we are not defining any types here, we are introducing a synonym (i.e. alias) for an abstraction of a type-id (i.e. type expression) involving template parameters.” 所以,我认为这其实是标准委员会他们的观点与选择,在C++11中,也是完全鼓励用using,而不用typedef的。

具体的可以看下Effective Modern C++

2.std::function函数包装器

std::function简介

std::function是一个函数包装器,该函数包装器模板能包装任何类型的可调用实体,如普通函数,函数对象,lamda表达式等。包装器可拷贝,移动等,并且包装器类型仅仅依赖于调用特征,而不依赖于可调用元素自身的类型。std::function是C++11的新特性,包含在头文件中。

一个std::function类型对象实例可以包装下列这几种可调用实体:函数、函数指针、成员函数、静态函数、lamda表达式和函数对象。std::function对象实例可被拷贝和移动,并且可以使用指定的调用特征来直接调用目标元素。当std::function对象实例未包含任何实际可调用实体时,调用该std::function对象实例将抛出std::bad_function_call异常。
std::function实战

std::function模板类声明

template<class _Rp, class …_ArgTypes>
class _LIBCPP_TEMPLATE_VIS function<_Rp(_ArgTypes…)>
: public __function::__maybe_derive_from_unary_function<_Rp(_ArgTypes…)>,
public __function::__maybe_derive_from_binary_function<_Rp(_ArgTypes…)>
{ … }

std::function模板类成员函数声明

typedef _Rp result_type;

// construct/copy/destroy:
_LIBCPP_INLINE_VISIBILITY
function() _NOEXCEPT { }
_LIBCPP_INLINE_VISIBILITY
function(nullptr_t) _NOEXCEPT {}
function(const function&);
function(function&&) _NOEXCEPT;
template<class _Fp, class = _EnableIfCallable<_Fp>>
function(_Fp);

#if _LIBCPP_STD_VER <= 14
template
_LIBCPP_INLINE_VISIBILITY
function(allocator_arg_t, const _Alloc&) _NOEXCEPT {}
template
_LIBCPP_INLINE_VISIBILITY
function(allocator_arg_t, const _Alloc&, nullptr_t) _NOEXCEPT {}
template
function(allocator_arg_t, const _Alloc&, const function&);
template
function(allocator_arg_t, const _Alloc&, function&&);
template<class _Fp, class _Alloc, class = _EnableIfCallable<_Fp>>
function(allocator_arg_t, const _Alloc& __a, _Fp __f);
#endif

function& operator=(const function&);
function& operator=(function&&) _NOEXCEPT;
function& operator=(nullptr_t) _NOEXCEPT;
template<class _Fp, class = _EnableIfCallable<_Fp>>
function& operator=(_Fp&&);

~function();

// function modifiers:
void swap(function&) _NOEXCEPT;

#if _LIBCPP_STD_VER <= 14
template<class _Fp, class _Alloc>
_LIBCPP_INLINE_VISIBILITY
void assign(_Fp&& __f, const _Alloc& __a)
{function(allocator_arg, __a, _VSTD::forward<_Fp>(__f)).swap(*this);}
#endif

// function capacity:
_LIBCPP_INLINE_VISIBILITY
_LIBCPP_EXPLICIT operator bool() const _NOEXCEPT {
  return static_cast<bool>(__f_);
}

// deleted overloads close possible hole in the type system
template<class _R2, class... _ArgTypes2>
  bool operator==(const function<_R2(_ArgTypes2...)>&) const = delete;
template<class _R2, class... _ArgTypes2>
  bool operator!=(const function<_R2(_ArgTypes2...)>&) const = delete;

public:
// function invocation:
_Rp operator()(_ArgTypes…) const;

#ifndef _LIBCPP_NO_RTTI
// function target access:
const std::type_info& target_type() const _NOEXCEPT;
template _Tp* target() _NOEXCEPT;
template const _Tp* target() const _NOEXCEPT;
#endif // _LIBCPP_NO_RTTI

从成员函数里我们知道std::function对象实例不允许进行==和!=比较操作,std::function模板类实例最终调用成员函数_Rp operator()(_ArgTypes…) const进而调用包装的调用实体。1、std::function包装函数指针

定义一个std::function<int(int)>对象实例

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

std::function对象实例包装函数指针

int (*fun_ptr)(int);

int fun1(int a){
return a;
}

int main(int argc, char *argv[]){
std::cout << “Hello world” << std::endl;

fun_ptr = fun1; //函数指针fun_ptr指向fun1函数
callback = fun_ptr; //std::function对象包装函数指针
std::cout << callback(10) << std::endl; //std::function对象实例调用包装的实体

return 0;

}

2、std::function包装函数

int fun1(int a){
return a;
}

int main(int argc, char *argv[]){
std::cout << “Hello world” << std::endl;

callback = fun1; //std::function包装函数
std::cout << callback(42) << std::endl; //std::function对象实例调用包装的调用实体

return 0;

}

3、std::function包装模板函数

template
T fun2(T a){
return a + 2;
}

int main(int argc, char *argv[]){
std::cout << “Hello world” << std::endl;

callback = fun2<int>; //std::function包装模板函数
std::cout << callback(10) << std::endl; //std::function对象实例调用包装的调用实体

return 0;

}

4、std::function包装函数对象

struct add{
int operator()(int x){
return x + 9;
}
};

int main(int argc, char *argv[]){
std::cout << “Hello world” << std::endl;

callback = add(); //std::function包装对象函数
std::cout << callback(2) << std::endl; //std::function对象实例调用包装的调用实体

return 0;

}

5、std::function包装lamda表达式

int main(int argc, char *argv[]){
std::cout << “Hello world” << std::endl;

auto fun3 = [](int a) {return a * 2;}; //lamda表达式
callback = fun3; //std::function包装lamda表达式
std::cout << callback(9) << std::endl; //std::function对象实例调用包装的调用实体

return 0;

}

6、std::function包装模板对象函数

template
struct sub{
T operator()(T a){
return a - 8;
}
};

int main(int argc, char *argv[]){
std::cout << “Hello world” << std::endl;

callback = sub<int>(); //std::function包装模板对象函数
std::cout << callback(2) << std::endl; //std::function对象实例调用包装的调用实体

return 0;

}

7、std::function包装模板对象静态函数

template
struct foo2{
static T foo(T a){
return a * 4;
}
};

int main(int argc, char *argv[]){
std::cout << “Hello world” << std::endl;

callback = foo2<int>::foo; //std::function包装模板对象静态函数
std::cout << callback(3) << std::endl; //std::function对象实例调用包装的调用实体

return 0;

}

8、std::function包装对象静态函数

struct foo1{
static int foo(int a){
return a * 3;
}
};

int main(int argc, char *argv[]){
std::cout << “Hello world” << std::endl;

callback = foo1::foo; //std::function包装对象静态函数
std::cout << callback(5) << std::endl; //std::function对象实例调用包装的调用实体

return 0;

}

9、std::function包装类成员函数

struct foo3{
int foo(int a){
return a * a;
}
};

int main(int argc, char *argv[]){
std::cout << “Hello world” << std::endl;

foo3 test_foo1;
callback = std::bind(&foo3::foo, test_foo1, std::placeholders::_1); //std::function包装类成员函数
std::cout << callback(9) << std::endl; //std::function对象实例调用包装的调用实体

return 0;

}

这里我们用到了std::bind,C++11中std::bind函数的意义就如字面上的意思一样,用来绑定函数调用的某些参数。std::bind的思想其实是一种延迟计算的思想,将可调用对象保存起来,然后在需要的时候再调用。而且这种绑定是非常灵活的,不论是普通函数还是函数对象还是成员函数都可以绑定,而且其参数可以支持占位符。

这里的std::placeholders::_1是一个占位符,且绑定第一个参数,若可调用实体有2个形参,那么绑定第二个参数的占位符是std::placeholders::_2。

10、std::function包装模板类成员函数

template
struct foo4{
T foo(T a){
return a * 6;
}
};

int main(int argc, char *argv[]){
std::cout << “Hello world” << std::endl;

foo4<int> test_foo2;
callback = std::bind(&foo4<int>::foo, test_foo2, std::placeholders::_1); //std::function包装模板类成员函数
std::cout << callback(7) << std::endl; //std::function对象实例调用包装的调用实体

return 0;

}

11、std::function拷贝、移动

int main(int argc, char *argv[]){
std::cout << “Hello world” << std::endl;

std::function<int(int)> callback2 = callback; //拷贝赋值运算符
std::cout << callback2(7) << std::endl;

std::function<int(int)>&& callback3 = std::move(callback); //移动赋值运算符
std::cout << callback3(7) << std::endl;
std::cout << callback(7) << std::endl;

std::function<int(int)> callback4(callback); //拷贝
std::cout << callback4(7) << std::endl;

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值