Pergunta

Eu quero ter um mapa que tem um tipo de chave homogêneo, mas os tipos de dados heterogêneos.

Eu quero ser capaz de fazer algo assim (pseudo-código):

boost::map<std::string, magic_goes_here> m;
m.add<int>("a", 2);
m.add<std::string>("b", "black sheep");

int i = m.get<int>("a");
int j = m.get<int>("b"); // error!

Eu poderia ter um ponteiro para uma classe base como o tipo de dados, mas preferiria não.

Eu nunca usei impulso antes, mas olhou para a biblioteca de fusão, mas não consigo descobrir o que eu preciso fazer.

Obrigado por sua ajuda.

Foi útil?

Solução

#include <map>
#include <string>
#include <iostream>
#include <boost/any.hpp>

int main()
{
    try
    {
        std::map<std::string, boost::any> m;
        m["a"]  = 2;
        m["b"]  = static_cast<char const *>("black sheep");

        int i = boost::any_cast<int>(m["a"]);
        std::cout << "I(" << i << ")\n";

        int j = boost::any_cast<int>(m["b"]); // throws exception
        std::cout << "J(" << j << ")\n";
    }
    catch(...)
    {
        std::cout << "Exception\n";
    }

}

Outras dicas

Como posso construir um de objetos de diferentes tipos?

Você não pode, mas você pode fingir muito bem. Em C / C ++ todas as matrizes são homogéneos (isto é, os elementos são todas do mesmo tipo). No entanto, com uma camada extra de engano você pode dar a aparência de um recipiente heterogênea (um recipiente heterogêneo é um recipiente onde os objetos contidos são de tipos diferentes).

Existem dois casos com containers heterogêneos.

O primeiro caso ocorre quando todos os objetos que você deseja armazenar em um recipiente são derivados publicamente de uma classe base comum. [...]

O segundo caso ocorre quando os tipos de objetos são disjuntos - eles não compartilham uma classe base comum
. A abordagem aqui é usar uma classe alça. O recipiente é um recipiente de objetos punho (por valor ou por ponteiro, sua escolha; por valor é mais fácil). Cada objeto punho sabe como "hold on a" (ou seja, manter um ponteiro para) um dos objetos que você deseja colocar no recipiente. Você pode usar uma única classe pega com vários tipos diferentes de ponteiros como dados de instância, ou uma hierarquia de classes punho que a sombra dos vários tipos que você deseja conter (requer o recipiente ser de ponteiros alça de classe base). A desvantagem dessa abordagem é que ela abre a classe identificador (es) para manutenção cada vez que você alterar o conjunto de tipos que podem ser contidas. A vantagem é que você pode usar a classe pega (es) para encapsular a maior parte da feiúra de gerenciamento de memória e vida útil do objeto. Assim, usando objectos de pega podem ser benéfica mesmo no primeiro caso.

boost :: qualquer fazer o truque para você?

Obrigado David, que era o que eu precisava. Aqui está a solução de trabalho.

#include <iostream>
using std::cout;
using std::endl;

#include <map>
#include <boost/any.hpp>

using boost::any_cast;
typedef std::map<std::string, boost::any> t_map;


int main(int argc, char **argv)
{

  t_map map;
  char *pc = "boo yeah!";

  map["a"] = 2.1;
  map["b"] = pc;

  cout << "map contents" << endl;
  cout << any_cast<double>(map["a"]) << endl;
  cout << any_cast<char*>(map["b"]) << endl;

  return 0;
}

Se você quiser um conjunto limitado de tipos a serem apoiados, Boost.Variant deve fazer o truque.

boost qualquer certamente funciona, mas acho que usando Int digitar Tecnologia como o tipo de chave de mapa de fusão é uma solução melhor. Nenhum tipo de apagamento e, possivelmente, mais rápido

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