A reinterpretar um ponteiro de função de membro é uma 'boa ideia'?
-
21-09-2019 - |
Pergunta
Eu tenho um tópico de trabalhador, que contém uma lista de 'ações de thread', e trabalha através deles como um quando.
template <class T> class ThreadAction
{
public:
typedef void (T::*action)();
ThreadAction(T* t, action f) :
func(f),obj(t) {}
void operator()() { (obj->*func)(); }
void (T::*func)();
T* obj;
};
Normalmente é chamado assim
myActionThread->addAction(
new ThreadAction<TheirClass>(this, &TheirClass::enable)
);
Que funcionou bem até
void TheirClass::enable()
foi alterado para
bool TheirClass::enable()
Infelizmente, não podemos alterá -lo novamente, porque outras coisas precisam do novo formato (e sobrecarga não podem diferir apenas pelo tipo de retorno).
Eu tentei
myActionThread->addAction(
new ThreadAction<TheirClass>(this,
reinterpret_cast<void(TheirClass::*)>(&TheirClass::enable)
)
);
O que parece funcionar muito bem, mas não tenho certeza de que reinterpretar um ponteiro de função como esse é um comportamento "definido", alguém pode aconselhar?
Solução
Isso é definitivamente não comportamento suportado e pode potencialmente fazer com que seu programa trave.
Basicamente, você precisa fazer um invólucro para TheirClass::enable()
Isso terá o tipo de retorno adequado. Uma linha simples simples será suficiente:
public:
void enableWrapper() { enable(); };
Então ligue:
myActionThread->addAction(
new ThreadAction<TheirClass>(this, &TheirClass::enableWrapper)
);
Se você não pode modificar TheirClass
Diretamente, crie uma subclasse ou classe auxiliar simples que implementa o invólucro.
Outras dicas
Err, pelo que eu entendi, você está lançando de um método que retorna um bool
para um método que retorna void
?
Isso pode ser perigoso, dependendo da convenção de chamada/retorno em uso. Você poderia Esqueça de exibir o valor de retorno - ou substituir o valor de um registro com o valor de retorno.
Não é uma boa ideia. Considere adicionar um parâmetro de modelo adicional para o tipo de retorno:
template <class T, typename RetType> class ThreadAction
{
public:
typedef RetType (T::*action)();
ThreadAction(T* t, action f) :
func(f),obj(t) {}
RetType operator()() { return (obj->*func)(); }
RetType (T::*func)();
T* obj;
};
Esta é uma aplicação de retornar vazio.
Geralmente acho que quando a pergunta é da forma "é _______ uma boa ideia?" A resposta é quase invariavelmente "não!"
Provavelmente isso é verdade sem contexto.