Estou experimentando escrever uma classe leve de sinais/observadores que tem a seguinte interface (implementação removida para simplificação):
template <typename ... ARGS>
class Signal
{
public:
void connect(AbstractSlot<ARGS...>& slot);
void disconnect(AbstractSlot<ARGS...>& slot);
void emit(const ARGS&...args);
//...
};
Que é usado, por exemplo, assim:
Signal<> signal1; //A signal with no parameters
Signal<int, int> signal2; //A signal with two int parameters
signal1.emit();
signal2.emit(10, 20);
Quero poder tornar minha classe opcionalmente thread-safe. Pensei em modificar meu modelo para aceitar uma classe de "política de bloqueio" que, por padrão, é "vazia".
struct NoLock
{
void lock() {}
void unlock() {}
};
Na minha cabeça, eu gostaria de poder usar o modelo de sinal modificado assim:
Signal<> signal1;
Signal<std::mutex> signal1Locked;
Signal<int, int> signal2;
Signal<int, int, std::mutex> signal2Locked;
O que exigiria que eu escrevesse o modelo assim:
template <typename ... ARGS, typename LockPolicy = NoLock>
class Signal;
Exceto que isso não é C++ válido (e eu entendo o porquê; como o compilador saberia a diferença entre os argumentos policy e variadic).
Minha pergunta é: como posso alcançar o que desejo em uma sintaxe que não seja muito confusa/complexa de usar?