jackyxinli Ответов: 2

Вопрос о делегате, реализованном в C++


Я нашел код делегата, который реализован в C++, и он скомпилирован под vs2017 и работает правильно.

#include<algorithm>
#include<functional>
#include<iostream>
#include<list>
#include<string>

using namespace std;

#ifdef _DEBUG
#define OUTPUT(info) cout<<info <<endl<<endl;
#else
#define OUTPUT(info)
#endif

template<class C, typename R, typename ...Args>
class delegate_class_mem
{
public:
	typedef R(C::*class_func_type)(Args...);

	delegate_class_mem(class_func_type fun, C* class_ptr)
		: _fun(fun), _class_ptr(class_ptr) {}

	R operator()(Args&&...args)
	{
		return (_class_ptr->*_fun)(args...);
	}

	bool operator==(const delegate_class_mem<C, R, Args...>&other) const
	{
		if (_class_ptr == other._class_ptr && _fun == other._fun)
			return true;
		return false;
	}

	template<typename T>
	bool operator==(const T&&)const
	{
		return false;
	}

private:
	C*  _class_ptr;
	class_func_type _fun;
};

template<typename ...T>
class delegate { };

template<typename R, typename ...Args>
class delegate<R(Args...)>
{
public:
	typedef std::function<R(Args...)> delegate_func;
	typedef std::list<delegate_func> function_list;
	typedef R(*func_type)(Args...);
	typedef delegate<R(Args...)>  this_type;

	delegate()
	{
		OUTPUT("function type:" << typeid(R(Args...)).name())
			OUTPUT("args count:" << sizeof...(Args))
	}

	~delegate()
	{
		func_list.clear();
	}

	this_type& operator-=(func_type func)
	{
		auto itr = std::find_if(func_list.begin(), func_list.end(),
			[&](delegate_func& f)->bool
		{
			auto _fun = f.target<R(*)(Args...)>();
			if (_fun && *_fun == func)
			{
				return true;
			}
			return false;
		});

		if (itr != func_list.end())
			func_list.erase(itr);

		return *this;
	}

	template<class C>
	this_type& operator-=(delegate_class_mem<C, R, Args...>&& class_mem_h)
	{
		auto itr = std::find_if(func_list.begin(), func_list.end(),
			[&](delegate_func& f)->bool
		{
			auto _fun = f.target<delegate_class_mem<C, R, Args...>>();
			if (_fun && *_fun == class_mem_h)
			{
				return true;
			}
			return false;
		});


		if (itr != func_list.end())
			func_list.erase(itr);

		return *this;
	}

	this_type& operator+=(func_type func)
	{
		bool exist = false;
		for (auto it = func_list.begin(); it != func_list.end(); it++)
		{
			auto _func = (*it).target<R(*)(Args...)>();
			if (_func && *_func == func)
			{
				exist = true;
				break;
			}
		}

		if (!exist)
			func_list.push_back(func);

		return *this;
	}

	template<class C>
	this_type& operator+=(delegate_class_mem<C, R, Args...>&& class_mem)
	{
		func_list.push_back(class_mem);
		return *this;
	}

	void operator()(Args&& ...args)
	{
		for (auto it = func_list.begin(); it != func_list.end(); it++)
		{
			try
			{
				(*it)(args...);
			}
			catch (exception ex)
			{
				//do something...
			}
		}
	}

private:
	function_list func_list;
};

template<typename C, typename R, typename ...Args>
auto makeDelegateClassHelper(R(C::*class_func_type)(Args...), C* class_ptr) ->delegate_class_mem<C, R, Args...>
{
	return delegate_class_mem<C, R, Args...>(class_func_type, class_ptr);
}

void func1(std::string& str)
{
	std::cout << "func1: " << str << endl;
}

void func2(std::string& str)
{
	std::cout << "func2: " << str << endl;
}

int main(int argc, char *argv[])
{
	std::string str("This is jacky_zz");
	delegate<void(std::string&)> _delegate;

	printf("func1: %p\n", func1);
	printf("func2: %p\n", func2);

	_delegate += func1;
	_delegate += func1;
	_delegate += func2;
	_delegate += func2;
	_delegate(str);

	return 0;
}


Но я использую G++(версия 7.4+) В MSYS2 или Ubuntu 18.0.4, у меня есть ошибки компиляции.

Что я уже пробовал:

Кто знает problemes есть? Теперь я в замешательстве. Кто может указать мне, как исправить проблемы?

Richard MacCutchan

Какие ошибки?

jackyxinli

$ g++ -Wall -std=делегат c++11 -o delegate.cpp
delegate.cpp: в лямбда-функции:
delegate.cpp:77:26: error: expected primary-expression before '(' token
auto _fun = f.target<R(*)(Args...)>();
^
delegate.cpp:77:28: error: expected primary-expression before ')' token
auto _fun = f.target<R(*)(Args...)>();
^
delegate.cpp:77:34: error: expected primary-expression before '...' token
auto _fun = f.target<R(*)(Args...)>();
^~~
delegate.cpp:77:40: error: expected primary-expression before ')' token
auto _fun = f.target<R(*)(Args...)>();
^
delegate.cpp: в лямбда-функции:
delegate.cpp:97:57: error: expected primary-expression before '>' token
авто _fun = Ф.цель&ЛТ;delegate_class_mem&ЛТ;С, Р, Аргументы...&ГТ;&ГТ;();
^~
делегата.КПП:97:60: ошибка: ожидается первичное-выражение до ')' маркер
авто _fun = Ф.цель&ЛТ;delegate_class_mem&ЛТ;С, Р, Аргументы...&ГТ;&ГТ;();
^
delegate.cpp: в функции-члена 'делегат&ЛТ;Р(Аргументы ...)&ГТ;::this_type&амп; делегировать&ЛТ;Р(Аргументы ...)&ГТ;::оператор+=(делегат&ЛТ;Р(Аргументы ...)&ГТ;::func_type)':
delegate.cpp:117:31: error: expected primary-expression before '(' token
auto _func = (*it).target<R(*)(Args...)>();
^
delegate.cpp:117:33: error: expected primary-expression before ')' token
auto _func = (*it).target<R(*)(Args...)>();
^
delegate.cpp:117:39: error: expected primary-expression before '...' token
auto _func = (*it).target<R(*)(Args...)>();
^~~
delegate.cpp:117:45: error: expected primary-expression before ')' token
auto _func = (*it).target<R(*)(Args...)>();
^

0x01AA

Может быть, это поможет: c++ - компиляция C++11 с g++ - переполнение стека[^]

jackyxinli

Я попробовал командовать как удар:
g++ -Wall -std=делегат c++11 -o delegate.cpp

или
g++ -Wall -std=делегат c++0x -o delegate.cpp

не сработать

2 Ответов

Рейтинг:
2

jackyxinli

#include<algorithm>
#include<functional>
#include<iostream>
#include<list>
#include<string>

using namespace std;

#ifdef _DEBUG
#define OUTPUT(info) cout<<info <<endl<<endl;
#else
#define OUTPUT(info)
#endif

template<class C, typename R, typename ...Args>
class delegate_class_mem
{
public:
	typedef R(C::*class_func_type)(Args...);

	delegate_class_mem(class_func_type fun, C* class_ptr)
		: _fun(fun), _class_ptr(class_ptr) {}

	R operator()(Args&&...args)
	{
		return (_class_ptr->*_fun)(args...);
	}

	bool operator==(const delegate_class_mem<C, R, Args...>&other) const
	{
		if (_class_ptr == other._class_ptr && _fun == other._fun)
			return true;
		return false;
	}

	template<typename T>
	bool operator==(const T&&)const
	{
		return false;
	}

private:
	C*  _class_ptr;
	class_func_type _fun;
};

template<typename ...T>
class delegate { };

template<typename R, typename ...Args>
class delegate<R(Args...)>
{
public:
	typedef std::function<R(Args...)> delegate_func;
	typedef std::list<delegate_func> function_list;
	typedef R(*func_type)(Args...);
	typedef delegate<R(Args...)>  this_type;

	delegate()
	{
		OUTPUT("function type:" << typeid(R(Args...)).name())
			OUTPUT("args count:" << sizeof...(Args))
	}

	~delegate()
	{
		func_list.clear();
	}

	this_type& operator-=(func_type func)
	{
		auto itr = std::find_if(func_list.begin(), func_list.end(),
			[&](delegate_func& f)->bool
		{
			auto _fun = f.template target<R(*)(Args...)>();
			if (_fun && *_fun == func)
			{
				return true;
			}
			return false;
		});

		if (itr != func_list.end())
			func_list.erase(itr);

		return *this;
	}

	template<class C>
	this_type& operator-=(delegate_class_mem<C, R, Args...>&& class_mem_h)
	{
		auto itr = std::find_if(func_list.begin(), func_list.end(),
			[&](delegate_func& f)->bool
		{
			auto _fun = f.template target<delegate_class_mem<C, R, Args...>>();
			if (_fun && *_fun == class_mem_h)
			{
				return true;
			}
			return false;
		});


		if (itr != func_list.end())
			func_list.erase(itr);

		return *this;
	}

	this_type& operator+=(func_type func)
	{
		bool exist = false;
		for (auto it = func_list.begin(); it != func_list.end(); it++)
		{
			auto _func = (*it).template target<R(*)(Args...)>();
			if (_func && *_func == func)
			{
				exist = true;
				break;
			}
		}

		if (!exist)
			func_list.push_back(func);

		return *this;
	}

	template<class C>
	this_type& operator+=(delegate_class_mem<C, R, Args...>&& class_mem)
	{
		func_list.push_back(class_mem);
		return *this;
	}

	void operator()(Args&& ...args)
	{
		for (auto it = func_list.begin(); it != func_list.end(); it++)
		{
			try
			{
				(*it)(args...);
			}
			catch (exception ex)
			{
				//do something...
			}
		}
	}

private:
	function_list func_list;
};

template<typename C, typename R, typename ...Args>
auto makeDelegateClassHelper(R(C::*class_func_type)(Args...), C* class_ptr) ->delegate_class_mem<C, R, Args...>
{
	return delegate_class_mem<C, R, Args...>(class_func_type, class_ptr);
}

void func1(std::string& str)
{
	std::cout << "func1: " << str << endl;
}

void func2(std::string& str)
{
	std::cout << "func2: " << str << endl;
}

int main(int argc, char *argv[])
{
	std::string str("This is jacky_zz");
	delegate<void(std::string&)> _delegate;

	printf("func1: %p\n", func1);
	printf("func2: %p\n", func2);

	_delegate += func1;
	_delegate += func1;
	_delegate += func2;
	_delegate += func2;
	_delegate(str);

	auto f = [](std::string& str) { std::cout << str << std::endl; };
	f(str);

	return 0;
}

Я не получил никаких ошибок, когда я добавляю "шаблон" перед целевой функцией. VS2017 & G++(7.4+) все в порядке.


k5054

Здесь есть подробное объяснение этого:
https://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords/17579889#17579889

См. также следующий комментарий, который также объясняет использование ключевого слова template в этой ситуации

jackyxinli

Во-первых, я также нахожу определение функции в библиотеке boost. Могу ли я спросить вас об этом синтаксисе, где я могу найти его в спецификации C++?

k5054

Мои знания о шаблонах не простираются далеко за пределы умения правильно произносить их!

Меня тоже интересовали причины такого синтаксиса, и я немного погуглил, чтобы посмотреть, что смогу найти. Упомянутая выше статья так казалось, объяснить. Если вы прокручиваете назад от этого, то есть очень длинный ответ, который цитирует стандарт.

Если вас действительно интересует что написано в стандарте смотрите http://eel.is/c++draft/temp#names-5 (Подробнее google-fu)

jackyxinli

Большое спасибо. Я нахожу статью также в stackoverflow[https://stackoverflow.com/questions/12676190/how-to-call-a-template-member-function]

Да, шаблон сложнее обычного синтаксиса в C++, поэтому неясность.

Рейтинг:
2

jackyxinli

Я использую команду компиляции, такую как blow:
g++ -Wall -std=делегат c++11 -o delegate.cpp

или
g++ -Wall -std=делегат c++0x -o delegate.cpp

не сработать