Sobrecarregado ponteiro função de membro de molde
-
11-09-2019 - |
Pergunta
Eu estou tentando ponteiros função de membro de loja por modelos como este: (Esta é uma versão simplificada do meu código real)
template<class Arg1>
void connect(void (T::*f)(Arg1))
{
//Do some stuff
}
template<class Arg1>
void connect(void (T::*f)())
{
//Do some stuff
}
class GApp
{
public:
void foo() {}
void foo(double d) {}
};
Então eu quero fazer como o seguinte para cada métodos sobrecarregados em GAPP:
connect(&GApp::foo);
Chamar esse para foo()
é ok, mas como eu posso chamar isso de foo(double d)
? Por que o seguinte não está funcionando?
connect((&GApp::foo)(double));
Ele vai me dar
erro de sintaxe: 'double' deve ser precedido por ')'
Eu não entendo a sintaxe que deve ser usado aqui. Este pode ser um qustion estúpido, mas qualquer um pode me ajudar nisso?
Solução
O seu código como escrito não compila. Eu tenho fazer algumas "suposições" sobre o que você queria fazer, e mudaram o código.
Para resumir, você pode chamar a função correta, especificando explicitamente o tipo de parâmetro de função:
connect<double> (&GApp::foo);
Se os métodos de conexão são membros de um modelo de classe, então é necessário especificar o tipo de classe uma vez:
template <typename T> class A
{
public:
template<class Arg1>
void connect(void (T::*f)(Arg1))
{
//Do some stuff
}
void connect(void (T::*f)())
{
//Do some stuff
}
};
class GApp
{
public:
void foo() {}
void foo(double d) {}
};
int main ()
{
A<GApp> a;
a.connect (&GApp::foo); // foo ()
a.connect<double> (&GApp::foo); // foo (double)
}
UPDATE:
Em resposta à nova amostra de código, toda a informação está sendo passada. O caso "raro" é o caso 'signal_void' como este é onde o sinal tem um argumento de modelo, mas a função de membro não. Portanto, caso especial que o exemplo e, em seguida, estamos a fazer. A seguir agora compila:
template <class Arg = void>
class signal {};
signal<double> signal_double;
signal<> signal_void;
// Arg1 is deduced from signal<Arg1> and then we use it in the declaration
// of the pointer to member function
template<class T, class Arg1>
void connect ( signal<Arg1>& sig, T& obj, void (T::*f)(Arg1) ) {}
// Add special case for 'void' without any arguments
template<class T>
void connect (signal<> & sig, T& obj, void (T::*f)()) {}
void bar ()
{
GApp myGApp;
//Connecting foo()
connect(signal_void, myGApp, &GApp::foo); // Matches second overload
//Connecting foo(double)
connect(signal_double, myGApp, &GApp::foo); // Matches first overload
}
Outras dicas
A C ++ Programming Language, 3E, Seção 7.7, P159:
Você pode obter o endereço de uma função sobrecarregada, atribuindo ou inicializar um ponteiro para a função. Nesse caso, o tipo de alvo é utilizado para seleccionar o conjunto de funções sobrecarregadas. Por exemplo:
void f(int);
int f(char);
void (*pf1)(int) = &f; // void f(int);
int (*pf2)(char) = &f; // int f(char);
void (*pf3)(char) = &f; // error: no void f(char)
Tanto quanto eu sei (não marcado), o mesmo se aplica a funções membro. Portanto, a solução é provavelmente a divisão em duas linhas:
connect((&GApp::foo)(double));
torna-se:
void (GApp::*tmp)(double) = &GApp::foo;
connect(tmp);
Nunca variáveis ??chamadas tmp
; -)
Eu acho que o elenco de newacct é seguro também, para exatamente a mesma razão. A transmissão para void (GApp::*)(double)
é definida para ser a mesma que a inicializar um temporária de tipo void (GApp::*)(double)
. Desde a expressão usada para inicializar é &GApp::foo
, eu esperaria a mesma mágica para aplicar ao elenco como se aplica a qualquer outra inicialização com uma função sobrecarregada. não Stroustrup não dizer "inicializar uma variável de ponteiro-para-função", diz ele "inicializar um ponteiro-para-função". De modo que deve incluir temporários.
Então, se você preferir um one-liner:
connect((void (GApp::*)(double))(&GApp::foo));
No entanto, eu estou supondo que o padrão tem a mesma ideia de consistência como eu, e eu não tenho verificado.
Você pode tentar explicitamente lançando o ponteiro, para deixá-lo saber qual selecionar, como este:
connect((void (GApp::*)(double))&GApp::foo);
IMPORTANTE: não testei-lo
Isso está funcionando,
typedef void (GApp::*MemberFunctionType)(double);
MemberFunctionType pointer = &GApp::foo;
connect(MemberFunctionType);
Por que isso?
Editar
hmm .. sim. É mesmo como a solução da newacct. Alguém pode dar uma solução pls?
Usando biblioteca boost :: function ...
#include <boost/function.hpp>
template<class Arg1>
void connect(boost::function1<void, Arg1*> fn)
{
//Do some stuff
}
template<class Arg1>
void connect(boost::function2<void, Arg1*, double> fn)
{
//Do some stuff
}
class GApp
{
public:
void foo() {}
void foo(double d) {}
};
int main()
{
boost::function1<void,GApp*> f1 = (void (GApp::*)(void)) &GApp::foo;
boost::function2<void,GApp*,double> f2 = (void (GApp::*)(double)) &GApp:foo;
connect(f1);
connect(f2);
return 0;
}
Meu código original é assim,
conectores ....
template<class T, class Arg1>
void connect(signal<Arg1>& sig,T& obj, void (T::*f)())
{
// sig.insert(new GFunction<T, Arg1>(&obj,f));
}
template<class T, class Arg1
void connect(signal<Arg1>& sig,T& obj, void (T::*f)(Arg1))
{
// sig.insert(new GFunction<T, Arg1>(&obj,f));
}
Sinais ...
signal<double> signal_double;
signal<> signal_void;
Aplicação ...
class GApp
{
public:
void foo() {}
void foo(double d) {}
};
Finalmente, conectando ...
//Connecting foo()
connect(signal_void, myGApp, &GApp::foo()); //Ok
//Connecting foo(double)
connect(signal_double, myGApp, &GApp::foo()); // but ERROR!
Há classs modelo para sinais (que não são mencionar aqui). Espero que agora está mais claro da situação. (Ou é mesmo que previouse?). Essa segunda conexão funcionará se não houver foo () (somente foo (double)). Essa é a coisa que meu código de me machucar. : (