Ponteiros de função de membro C ++ e algoritmo STL
-
12-09-2019 - |
Pergunta
Eu tenho uma classe de functor abstrata que sobrecarrega o operador () e objetos derivados que a implementam.
Eu tenho uma função (parte de outra classe) que tenta fazer uma variedade dessas classes de functor e tenta passar um ponteiro para uma função de membro para o algoritmo STD para_each (), aqui está uma visão geral do que estou fazendo:
EDIT: Eu o limpei e coloquei o pequeno exemplo antigo para maior clareza.
class A{
operator()(x param)=0;
operator()(y param)=0;
}
class B: public A{
operator()(x param); //implemented
operator()(y param);
}
...// and other derived classes from A
void ClassXYZ::function(A** aArr, size_t aSize)
{
...//some code here
for(size_t i = 0; i< aSize; i++){
A* x = aArr[i];
for(v.begin(), v.end(), ...//need to pass pointer/functor to right operator() of x here
..//other code
}
Eu tentei algumas maneiras e não consigo descobrir como fazê -lo funcionar, preciso usar o tipo abstrato, pois poderia ter diferentes tipos derivados, mas todos terão que implementar o mesmo operador () (Param X ) função.
Eu só preciso da função for_each () para poder chamar o operador de função do membro () (param x). Eu tenho uma função diferente na qual ela tem implementações concretas e simplesmente passa uma instância delas e funciona. Estou tentando obter um efeito semelhante aqui, mas sem o conhecimento de quais classes concretas recebem.
O que estou fazendo errado?
Solução
Se eu entendi o que você quer fazer, existem alguns erros no seu snippet de código:
sizeof aArr
está errado, você precisa passar o tamanho explicitamente (notado por Chrisw)- Ausência de
virtual
especificador na declaração original deoperator()()
- Não tenho certeza de onde seu
for
o loop termina como não há correspondência}
(Eu suspeito que não deveria estar lá)
Aqui está algum código que percorre uma matriz de A
(ou A
-Derived) Objetos e chamados operator()
em cada um, passando por um argumento aprovado como o param
parâmetro:
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
typedef double param; // Just for concreteness
class A {
public:
virtual void operator()(param x) = 0;
};
class B : public A {
public:
void operator()(param x) { cerr << "This is a B! x==" << x << ".\n"; }
};
void function(A** aArr, size_t n, param theParam) {
void (A::*sFunc)(param x) = &A::operator();
for_each(aArr, aArr + n, bind2nd(mem_fun(sFunc), theParam));
}
int main(int argc, char** argv) {
A* arr[] = { new B(), new B(), new B() };
function(arr, 3, 42.69);
delete arr[0];
delete arr[1];
delete arr[2];
return 0;
}
mem_fun()
é necessário para converter um ponteiro de função de membro de 1 parâmetro em um objeto de função de 2 parâmetros; bind2nd()
então produz a partir desse objeto de função de 1 parâmetro que corrige o argumento fornecido a function()
Como o segundo argumento. (for_each()
requer um ponteiro de função ou objeto de função de 1 parâmetro.)
EDITAR: Baseado em Resposta de Alex Tingle, Deduzir que você pode ter desejado function()
fazer muitas coisas em um único A
-Objeto derivado. Nesse caso, você vai querer algo como:
void function(A** aArr, size_t n, vector<param> const& params) {
for (size_t i = 0; i < n; ++i) {
void (A::*sFunc)(param x) = &A::operator();
for_each(params.begin(), params.end(), bind1st(mem_fun(sFunc), aArr[i]));
}
}
Outras dicas
Você quer algo assim ...
std::for_each(
it->second.begin(),
it->second.end(),
std::bind1st(std::mem_fun(&A::operator()),x)
);
A expressão "bar.*Fn" não se avalia em ponteiro de função regular ou não membro. Portanto, você precisa chamar uma função de ligação (std :: tr1 :: bind ou boost :: bind) para obter essa função.
Não consegui fazer funcionar usando o formato atual, acho que não gosta do fato de que estou usando um ponteiro para uma função de membro da base e tentando chamar uma implementação de classes derivadas como essa.
Em vez disso, modifiquei o código para incluir funções virtuais puras na classe base que retornarão funções para cada classe derivada quando implementada. Não consigo pensar em mais nada que funcione. Mas compila como este.
Mas estou curioso para saber se alguém tiver uma solução para o problema original sem ter que usar os métodos virtuais "Criar functor" na classe base.