Pergunta

O que há de errado com o pequeno programa seguinte que passa um objeto de função?

#include <iostream>
#include <functional>

void foo(const std::unary_function<const std::string&, void>& fct) {
  const std::string str = "test";
  fct(str); // error
}

class MyFct : public std::unary_function<const std::string&, void> {
public:
  void operator()(const std::string& str) const {
    std::cout << str << std::endl;
  }
};

int main(int argc, char** argv){
  MyFct f;
  foo(f);
  return 0;
}

Estou recebendo o seguinte erro na linha 6:

 no match for call to 
`(const std::unary_function<const std::string&, void>) (const std::string&)'
Foi útil?

Solução

Um erro comum. unary_function e binary_function são apenas duas estruturas que agregam typedefs

argument_type
result_type

e respectivamente

first_argument_type
second_argument_type
result_type

Não mais. Eles são para conveniência de criadores de tipos de função de objeto, para que eles não têm que fazer os mesmos. Mas eles não se comportam polimórfico. O que você quer é função wrapper objeto. boost::function vem à mente:

void foo(boost::function<void(const std::string&)> const& fct) {
  const std::string str = "test";
  fct(str); // no error anymore
}

Ou torná-lo um modelo

template<typename FunctionObject>
void foo(FunctionObject const& fct) {
  const std::string str = "test";
  fct(str); // no error anymore
}

Você pode levá-lo por valor e, em seguida, retornar a cópia de foo se usá-lo para aplicá-la a uma sequência. O que permitiria que o objeto função para atualizar algumas variáveis ??de estado entre os seus membros. for_each é um exemplo que faz isso assim. Geralmente, de qualquer maneira, eu iria aceitá-los por valor, porque eles são geralmente pequenas e copiá-los permite uma maior flexibilidade. Então eu faço

template<typename FunctionObject>
void foo(FunctionObject fct) {
  const std::string str = "test";
  fct(str); // no error anymore
}

Você será capaz de tirar uma cópia da FCT e salvá-lo em algum lugar, e operador de fct () pode ser não-const e atualizar alguns membros (que faz parte de todo o ponto de operator()). Lembre-se você tomar um objeto de função por referência const, você geralmente não pode copiá-lo, porque o usuário poderia ter passado uma função. Copiá-lo, em seguida, vai tentar declarar localmente uma função em vez de um ponteiro de função local. No entanto, aceitando por valor irá aceitar um ponteiro de função em vez quando uma função foi aprovada, o que pode seguramente ser copiado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top