Идеальная пересылка аргументов шаблона

Я написал следующую реализацию для общей системы сигналов / слотов:

template< typename... Args >
class Signal : NonCopyable
{
public:

typedef std::function< void (Args...) > Delegate;

void connect(const Delegate& delegate);
void operator ()(Args&&... args) const;

private:

std::list< Delegate > _delegates;
};

template< typename... Args >
void Signal< Args... >::connect(const Delegate& delegate)
{
_delegates.push_front(delegate);
}

template< typename... Args >
void Signal< Args... >::operator ()(Args&&... args) const
{
for (const Delegate& delegate : _delegates)
delegate(std::forward< Args >(args)...);
}

После этого я проверил свой класс, используя следующие простые случаи:

Signal< int > signal;

// Case 1
signal(0);

//Case 2
int i(0);
signal(i);

Случай 1 компилируется без проблем. Случай 2, с другой стороны, генерирует следующую ошибку в GCC 4.7.2:

/home/pmjobin/Workspace/main.cpp:1196:10: error: cannot bind ‘int’ lvalue to ‘int&&’
/home/pmjobin/Workspace/main.cpp:82:6: error:   initializing argument 1 of ‘void Signal<Args>::operator()(Args&& ...) const [with Args = {int}]’

Я понимаю, что проблема связана с совершенной пересылкой (и моим неправильным пониманием последней). Тем не менее, я вдохновился от std :: make_shared () & Реализации std :: make_tuple (), и я не вижу никакой разницы в том, как я пересылаю аргументы с переменным числом аргументов делегатам. Единственное заметное отличие состоит в том, что make_shared () и make_tuple () являются шаблонами функций, а не шаблонами классов, такими как реализация Signal выше.

— РЕДАКТИРОВАТЬ —

В ответ на различные комментарии, вот новая версия реализации класса Signal, которая не страдает от вышеупомянутых проблем. Кроме того, теперь возможно отключить делегатов с помощью непрозрачного токена, возвращаемого функцией соединения. Результат может быть не таким гибким и мощным, как другие реализации (например, boost :: signal), но, по крайней мере, он имеет преимущество, заключающееся в простоте и легкости.

template< typename Signature >
class Signal : NonCopyable
{
public:

typedef std::function< Signature > Delegate;

class DisconnectionToken
{
DisconnectionToken(typename std::list< Delegate >::iterator it)
: _it(it)
{}

typename std::list< Delegate >::iterator _it;

friend class Signal;
};

DisconnectionToken connect(const Delegate& delegate);
void disconnect(DisconnectionToken& token);

template< typename... Args >
void operator ()(Args&&... args) const;

private:

std::list< Delegate > _delegates;
};

template< typename Signature >
typename Signal< Signature >::DisconnectionToken Signal< Signature >::connect(const Delegate& delegate)
{
_delegates.push_front(delegate);
return DisconnectionToken(_delegates.begin());
}

template< typename Signature >
void Signal< Signature >::disconnect(DisconnectionToken& token)
{
if (token._it != _delegates.end())
{
_delegates.erase(token._it);
token._it = _delegates.end();
}
}

template< typename Signature >
template< typename... Args >
void Signal< Signature >::operator ()(Args&&... args) const
{
for (const Delegate& delegate : _delegates)
delegate(std::forward< Args >(args)...);
}

6

Решение

Проблема в том, что вы явно указываете параметр шаблона как int, Как сказал Наваз, Args&&... расширяется в int&& и вы не можете связать lvalue со ссылкой на rvalue.

Идеальная пересылка работает потому, что при вызове функции (например) без указания аргументов шаблона они выводятся либо & или же && и затем ссылки сворачиваются (читайте о свертывании ссылок, если вы не знаете, что это такое). Вы делать явно указывайте это, так что вы запрещаете сворачивание ссылок и все испортите.

Одна вещь, которую вы могли бы сделать, это дать operator() это собственный список аргументов шаблона:

template<typename... Args2>
void operator ()(Args2&&... args) const;

...

template< typename... Args >
template< typename... Args2 >
void Signal< Args... >::operator ()(Args2&&... args) const
{
for (const Delegate& delegate : _delegates)
delegate(std::forward< Args2 >(args)...);
}

Таким образом, вы можете позволить свертыванию ссылок позаботиться об этом за вас.

5

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

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

По вопросам рекламы [email protected]