Замена указателя на шаблонную функцию универсальным типом

Я написал следующую обертку для std::bind а также std::queue:

#include "Queue.h"
template<class T>
Queue<T>::Queue(T* input)
{
instance = input;
}

template<class T> template<typename... Args>
int Queue<T>::push(int (T::*func)(Args... args), Args... args)
{
queue.push(std::bind(func, instance, args...));
return queue.size();
}

template<class T>
int Queue<T>::pop()
{
if(!queue.empty())
{
queue.front()();
queue.pop();
return queue.size();
}
return 0;
}

template<class T>
bool Queue<T>::empty()
{
return queue.empty();
}

template<class T>
size_t Queue<T>::size()
{
return queue.size();
}

со следующим заголовком:

#ifndef QUEUE_H_
#define QUEUE_H_

#include <functional>
#include <queue>

template <class T>
class Queue
{
private:
std::queue<std::function<void()>> queue;    /**< the messaging queue, appended to using enqueue(), popped from using dequeue() */
T* instance;

public:

Queue(T*);

template<typename... Args>
int enqueue(int (T::*f)(Args... args), Args... args);

int dequeue();

bool empty();

size_t size();
};

#endif

Это позволяет мне добавлять связанные выражения функции в очередь и высовывать их потом (queue->push<int>(&Object::jumpAround, 10); а также queue->pop()). Проблема в том, что я не смог найти общий объектный и функциональный указатель, который позволил бы мне реализовать это без <class T> шаблон.

Я знаю, что использование шаблонов, вероятно, будет самым безопасным и лучшим подходом здесь, но из-за дизайна кода, реализующего эту очередь, мне нужно от него избавиться. Есть идеи?

Я думаю, это должно быть как-то возможно, потому что std::bindПервый параметр может быть любой функцией, а второй — любым объектом.

2

Решение

Если я понимаю, вот что вам нужно:

class Queue
{
private:
std::queue<std::function<void()>> queue;    /**< the messaging queue, appended to using enqueue(), popped from using dequeue() */
public:

// pass in the instance of the object and simply allow the compiler to deduce the function pointer nastiness...
template<typename T, typename F, typename... Args>
void enqueue(T instance, F func, Args... args)
{
queue.push(std::bind(func, instance, args...));
}

int dequeue()
{
if(!queue.empty())
{
queue.front()();
queue.pop();
}
}
};

Ох, и как это использовать:

struct foo
{
void bar(int a)
{
std::cout << "foo::bar: " << a << std::endl;
}
};

struct bar
{
void foo(int a, int c)
{
std::cout << "bar::foo: " << (a  + c)<< std::endl;
}
};

int main(void)
{
Queue q;
foo f;
bar b;
q.enqueue(&f, &foo::bar, 10);
q.enqueue(&b, &bar::foo, 10, 11);

q.dequeue();
q.dequeue();
}

Должен выводить:

foo::bar: 10
bar::foo: 21

Или, что еще лучше, измените сигнатуру своей функции и разрешите пользователям ставить в очередь std::function! Это «нормальный» способ (см., Например, boost::asio::io_service::post.)

РЕДАКТИРОВАТЬ: Вот простой пример:

// Let the compiler do all the hard work for you..
template<typename T>
void enqueue(T f)
{
queue.push(f);
}

Теперь, чтобы отправить любую функцию в эту очередь …

// Here you are posting the functor itself...
q.enqueue(std::bind(&bar::foo, &b, 15, 12));
3

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector