Pergunta

Eu gostaria de saber o que é melhor usar na minha situação e por quê. Primeiro de tudo, ouvi dizer que o uso do RTTI (tipoID) é ruim. Alguém poderia explicar por quê? Se eu sei exatamente tipos, o que há de errado em compará -los em tempo de execução? Além disso, há algum exemplo de como usar o boost :: type_of? Eu não encontrei nenhum pesquisando no poderoso Google :) Outra solução para mim é a especialização, mas eu teria especializar pelo menos 9 tipos de novos métodos. Aqui está um exemplo do que eu preciso:

Eu tenho esta aula

  template<typename A, typename B, typename C>
  class CFoo
  {
     void foo()
     {
       // Some chunk of code depends on old A type
     }

  }

Então, eu preciso verificar o tipo (o que eu ouvi é ruim) e fazer essas três realizações em exemplo como:

 void foo()
   {
      if (typeid(A) == typeid(CSomeClass)
       // Do this chunk of code related to A type
      else
      if (typeid(B) == typeid(CSomeClass)
       // Do this chunk of code related to B type
      else
      if (typeid(C) == typeid(CSomeClass)
       // Do this chunk of code related to C type
   }

Então, qual é a melhor solução? Não quero me especializar para todos os A, B, C, porque todo tipo tem 3 especializações, então obterei 9 métodos ou apenas essa verificação do tipo.

Foi útil?

Solução

É ruim porque

  1. A, B e C são conhecidos em tempo de compilação, mas você está usando um mecanismo de tempo de execução. Se você invocar TypeId, o compilador garantirá metadados nos arquivos de objeto.
  2. Se você substituir "faça esse pedaço de código relacionado a um tipo" por código real que utiliza a interface do CSomeclass, verá que não poderá compilar o código no caso A! = CSomeclass e ter uma interface incompatível. O compilador ainda tenta traduzir o código, mesmo que nunca seja executado. (Veja o exemplo abaixo)

O que você normalmente faz é levar em consideração o código em modelos de função separados ou funções estáticas de membros de classes que podem ser especializadas.

Mau:

template<typename T>
void foo(T x) {
    if (typeid(T)==typeid(int*)) {
        *x = 23; // instantiation error: an int can't be dereferenced
    } else {
        cout << "haha\n";
    }
}
int main() {
    foo(42); // T=int --> instantiation error
}

Melhor:

template<typename T>
void foo(T x) {
    cout << "haha\n";
}
void foo(int* x) {
    *x = 23;
}
int main() {
    foo(42); // fine, invokes foo<int>(int)
}

Saúde, s

Outras dicas

Bem, geralmente as soluções podem surgir sem RTTI. Ele "pode" mostrar que você não pensou no design do software corretamente. Isso é mau. Às vezes rtti posso Seja uma coisa boa.

Não há algo estranho no que você quer fazer. Você não poderia criar um modelo intermediário projetado algo como a seguir:

template< class T > class TypeWrapper
{
  T t;
public:
  void DoSomething()
  {
  }
};

Em seguida, se especialize parcialmente pelas funções que você deseja da seguinte maneira:

template<> class TypeWrapper< CSomeClass >
{
  CSomeClass c;
public:
  void DoSomething()
  {
     c.DoThatThing();
  }
};

Então, em sua classe, defina acima, você faria algo como ...

modelo

  class CFoo
  {
     TypeWrapper< A > a;
     TypeWrapper< B > b;
     TypeWrapper< C > c;
     void foo()
     {
       a.DoSomething();
       b.DoSomething();
       c.DoSomething();
     }

  }

Dessa forma, ele realmente faz algo na chamada "doSomething" se estiver passando pelo modelo parcialmente especializado.

O problema está nos pedaços de código que você escreve para cada especialização.

Não importa se você escreve (longamente)

void foo()
{
   if (typeid(A) == typeid(CSomeClass)
    // Do this chunk of code related to A type
   else
   if (typeid(B) == typeid(CSomeClass)
    // Do this chunk of code related to B type
   else
   if (typeid(C) == typeid(CSomeClass)
    // Do this chunk of code related to C type
}

ou

void foo()
{
   A x;
   foo_( x );
   B y;
   foo_( y );
   C z;
   foo_( z );
}
void foo_( CSomeClass1& ) {}
void foo_( CSomeClass2& ) {}
void foo_( CSomeClass3& ) {}

A vantagem do segundo caso é que, quando você adiciona uma classe D, você é lembrado pelo compilador de que há uma sobrecarga para que você tenha falta o que você deve escrever. Isso pode ser esquecido na primeira variante.

Receio que isso não funcione em primeiro lugar. Esses "pedaços de código" precisam ser compiláveis, mesmo que o tipo não seja csomeclass.

Eu não acho que o tipo_of também ajudará (se for o mesmo que o Auto e o dtype em C ++ 0x).

Eu acho que você poderia extrair esses três pedaços para funções separadas e sobrecarregar cada uma para o csomeclass. (Editar: Oh, existem else if's. Então você pode realmente precisar de muitas sobrecargas/especialização. Para que serve esse código?)

Edit2: parece que seu código espera fazer o equivalente ao seguinte, onde int é o tipo especial:

#include <iostream>

template <class T>
bool one() {return false; }

template <>
bool one<int>() { std::cout << "one\n"; return true; }

template <class T>
bool two() {return false; }

template <>
bool two<int>() { std::cout << "two\n"; return true; }

template <class T>
bool three() {return false; }

template <>
bool three<int>() { std::cout << "three\n"; return true; }

template <class A, class B, class C>
struct X
{
    void foo()
    {
        one<A>() || two<B>() || three<C>();
    }
};

int main()
{
    X<int, double, int>().foo(); //one
    X<double, int, int>().foo();  //two
    X<double, double, double>().foo(); //...
    X<double, double, int>().foo(); //three
}

Eu acho que você entendeu suas abstrações em algum lugar.

Eu tentaria redefinir A, B&C em termos de interfaces que eles precisam expor (classes base abstratas em C ++ com métodos virtuais puros).

O modelo permite basicamente o pato, mas parece que o CFOO sabe muito sobre as aulas da AB&C.

typeId é ruim porque:

  1. O TypeID pode ser caro, binários inchados, carrega informações extras que não devem ser necessárias.
  2. Nem todos os compiladores suportam
  3. Está basicamente quebrando a hierarquia da classe.

O que eu recomendaria é refatorar: Remova o modelo, em vez disso, defina interfaces para A, B&C e faça o CFOO levar essas interfaces. Isso o forçará a refatorar o comportamento para que os B&C sejam na verdade tipos coesos.

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