Tôi đã viết thực hiện sau đây cho một hệ thống tín hiệu/khe chung:Perfect chuyển tiếp của variading mẫu đối số
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)...);
}
Sau đó, tôi đã kiểm tra lớp học của tôi bằng cách sử dụng các trường hợp đơn giản sau đây:
Signal<int> signal;
// Case 1
signal(0);
//Case 2
int i(0);
signal(i);
Trường hợp 1 biên dịch mà không có vấn đề. Trường hợp 2, mặt khác, tạo ra lỗi sau theo 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}]’
Tôi hiểu vấn đề có liên quan đến việc chuyển tiếp hoàn hảo (và sự hiểu lầm của tôi về sau). Tuy nhiên, tôi đã lấy cảm hứng từ std :: make_shared() & std :: make_tuple() triển khai và tôi không thấy bất kỳ sự khác biệt trong cách tôi chuyển tiếp các đối số variadic cho các đại biểu. Điểm khác biệt đáng chú ý nhất là make_shared() và make_tuple() là các khuôn mẫu hàm chứ không phải là một mẫu lớp như thực hiện Signal ở trên.
- EDIT -
Để đối phó với những ý kiến khác nhau, đây là một phiên bản mới của việc thực hiện lớp tín hiệu mà không bị các vấn đề nói trên. Ngoài ra, bây giờ có thể ngắt kết nối các đại biểu bằng mã thông báo mờ được trả về bởi hàm kết nối. Kết quả có thể không linh hoạt và mạnh mẽ như các triển khai khác ngoài đó (chẳng hạn như boost :: signal), nhưng ít nhất, nó có lợi ích là đơn giản và nhẹ.
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)...);
}
'Args && ... args' về cơ bản là' int && args'. – Nawaz
@Nawaz yeah, tôi đã bỏ lỡ rằng anh ta đã chỉ định rõ ràng nó ở trên. Không bao giờ nói những gì tôi vừa nói. Vâng, chuyển tiếp hoàn hảo chủ yếu chỉ hoạt động khi bạn cho phép loại mẫu được suy luận. –
Những gì OP cần (hoặc _can_) làm là có một 'Args ...' riêng biệt cho toán tử '()'. –