Sem reflection

Caloni, 2011-05-18 computer ccpp blog

Em C++ não temos (ainda) a possibilidade de listarmos, por exemplo, a lista de métodos de um determinado tipo, a fim de chamá-lo pelo nome em tempo de execução. Algo assim:

class MyClass
{
public:
  void Method1();
  void Method2();
  void Method3();
};

int main()
{
  MyClass c;
  if( auto m = typeid(c). methods. getaddresof( "Method1" ) )
  {
    m();
  }
}

// Update 2026-03-13
// Porém, a proposta do C++ 26 deixaria as coisas
// um pouco mais apimentadas e confusas. Segue pseudocódigo
// baseado na proposta P2996.
template <typename T>
auto criar_mapa_de_metodos() {
  std::unordered_map<std::string, std::function<void(T&)>> mapa;
  
  // O 'template for' itera sobre os membros da classe em tempo de compilação
  template for (constexpr auto m : std::meta::members_of(^T)) {
    if (std::meta::is_function(m)) {
      mapa[std::meta::name_of(m)] = [](T& obj) { 
        // [: m :] "desenrola" o metadado de volta para o código real
        obj.[: m :](); 
      };
    }
  }
  return mapa;
}

Agora voltando para o passado.

OK, foi apenas um exemplo tosco de como seria um reflection em C++.

Porém, existem algumas maneiras de contornar esse problema. A solução, é claro, depende de qual problema você está tentando resolver.

Vamos supor, por exemplo, que você queira cadastrar funções para serem chamadas de maneira uniforme pelo prompt de comando. Vamos chamar nossa classe tratadora de CommandPrompt.

typedef void (Method*)(vector<string>& args);

class CommandPrompt
{
public:
  void Add(string name, Method m); // adiciona novo método
  void Interact(ostream& os, istream& is); // começa interação com usuário
};

Internamente, para armazenar as funções de acordo com o nome dado, basta criarmos um mapeamento entre esses dois tipos e fazemos a amarração necessária para o método principal de parseamento:

// uma variável desse tipo armazena todas as funções
typedef map<string, Method> MethodList;

void CommandPrompt::Interact(ostream& os, istream& is)
{
  while( is )
  {
    string func;
    vector<string> args;

    if( ParseLine(is, func, args) )
    {
      // se a função desejada está em nossa lista,
      // podemos chamá-la, mesmo sem conhecer qual é
      if( Method m = m_funcs[func] )
        m(args);
    }
  }
}

Essa solução não é exatamente um reflection, mas apenas parte do que o verdadeiro reflection possibilita. Existem outras funcionalidades, como traits, que a STL já consegue se virar razoavelmente bem, por exemplo.

[os_agentes_do_destino] [houaiss_no_kindle]