Pergunta

Eu estou usando modelos C ++ para passar em functors estratégia para mudar o comportamento da minha função. Funciona bem. O functor eu passar é uma classe apátridas sem armazenamento e ele só sobrecarrega o operador () no caminho functor clássico.

template <typename Operation> int foo(int a) 
{
int b=Operation()(a);
/* use b here, etc */
}

Eu faço isso muitas vezes, e ele funciona bem, e muitas vezes eu estou fazendo modelos com 6 ou 7 functors templated passaram em!

No entanto eu me preocupo tanto sobre a elegância de código e também a eficiência. O functor é apátrida assim que eu assumir a operação () construtor é gratuito e a avaliação do functor é tão eficiente quanto uma função inline, mas como todos C ++ programadores que eu sempre tenho algumas dúvidas irritante.

A minha segunda pergunta é se eu poderia usar uma abordagem functor alternativo .. aquele que não substitui o operador (), mas faz tudo no construtor como um efeito colateral! Algo como:

struct Operation {
  Operation(int a, int &b) { b=a*a; }
};
template <typename Operation> int foo(int a) 
 {
   int b;
   Operation(a,b);
    /* use b here, etc */
 }

Eu nunca vi ninguém usar um construtor como o "trabalho" de um functor, mas parece que ele deve funcionar. Existe alguma vantagem? Qualquer desvantagem? Eu gosto da remoção do parêntese dobrou estranho "Operador () (a)", mas isso é provavelmente apenas estética.

Foi útil?

Solução

Qualquer desvantagem?

  • ctors não retornam qualquer valor útil -. Não pode ser usado em chamadas encadeadas (por exemplo foo (bar ())
  • Eles podem jogar.
  • Projeto ponto de vista - ctors são funções criação do objeto, não é realmente concebido para ser burros de carga.

Outras dicas

  1. Compiladores realmente em linha do construtor vazio da Operação (pelo menos gcc em situações semelhantes não, exceto quando você desativou a otimização)
  2. A desvantagem de fazer tudo no construtor é que você não pode criar um functor com algum estado interno dessa maneira - por exemplo. functor para a contagem do número de elementos satisfaçam um predicado. Além disso, usando um método de um objeto real como um functor permite armazenar a instância dele para execução posterior, algo que você não pode fazer com a sua abordagem construtor.

A partir de um desempenho pov o código demonstrado com ficar completamente otimizado tanto com VC e GCC. No entanto, uma estratégia melhor, muitas vezes é levar o functor como um parâmetro, de que maneira você obter muito mais flexibilidade e características de desempenho idênticas.

Eu recomendo definindo functor que trabalham com o STL-contentores, ou seja, eles devem implementar operator (). (Na sequência da API do idioma que você está usando é sempre uma boa idéia.)

Isso permitirá que seus algoritmos para ser muito genérico (passar em funções, functors, STL-Bind, boost :: função, boost :: bind, boost :: lambda, ...) que é o que normalmente quer.

Desta forma, você não precisa especificar o tipo de functor como um parâmetro do modelo, apenas construir uma instância e passá-lo em:

my_algorithm(foo, bar, MyOperation())

Não parece qualquer ponto na implementação do construtor em outra classe.
Tudo o que você está fazendo é quebrar encapsulamento e criação de sua classe para o abuso.

O construtor deve inicializar o objeto em um bom estado, tal como definido pela classe. Você está permitindo que outro objeto para inicializar sua classe. Que garantias você tem que esta classe de modelo sabe como inicializar sua classe corretamente? Um usuário de sua classe pode fornecer qualquer objeto que poderia mexer com o estado interno de seu objeto de modo que não se destinam.

A classe deve ser auto-contido e inicializar-se a um estado bom. O que você parece estar fazendo é brincar com modelos apenas para ver o que eles podem fazer.

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