Existe alguma maneira de converter um std :: any contendo um ponteiro derivado em um ponteiro base, sem conhecer o tipo derivado?

8

Digamos que eu tenho um std::anyobjeto que pode ou não conter um ponteiro para alguma classe derivada de uma determinada classe base B. Existe alguma maneira de fazer algo que:

  1. Retorna a B *, se o std::anyobjeto mantiver algo convertível em B *, ou
  2. Lança uma exceção, se não?

Parece que dynamic_caste std::any_castcada fornecer metade desta funcionalidade, mas eu não vejo nenhuma maneira de colocar os dois juntos.

Estou ciente de que posso fazer isso funcionar de várias maneiras que envolvam enumerar explicitamente todos os tipos conversíveis B *, mas essa é a mãe de todas as violações DRY.


Exemplo de caso de uso:

std::vector<std::any> setupTools(const std::string & confFile)
{
  std::vector<std::any> myTools;

  auto conf = parse(confFile);

  for(std::string & wrenchInfo : conf["Wrenches"])
  {
    Wrench::setup(myTools, wrenchInfo);
  }    

  for(std::string & hammerInfo : conf["Hammers"])
  {
    Hammer::setup(myTools, hammerInfo);
  }

   // 25 more kinds of tools
}

Factory1::init(const std::vector<std::any> & tools)
{
  m_wrench = any_get<Wrench *>(tools);
  m_hammer = any_get<Hammer *>(tools);
  m_saw = any_get<Saw *>(tools);
}

Factory2::init(const std::vector<std::any> & tools)
{
  m_wrench = any_get<TorqueWrench *>(tools);
}

Factory3::init(const std::vector<std::any> & tools)
{
  m_saw = any_get<CordlessReciprocatingSaw *>(tools);
}

Não quero incluir um monte de código padrão listando todos os tipos de serra existentes, para que eu possa pegar uma serra - qualquer Saw - para usar Factory1.

Daniel McLaury
fonte
1
Você pode dar uma explicação sobre por que você precisa usar std::anyisso e o que você está tentando resolver em geral? Isso soa como um problema muito estranho e provavelmente há uma melhor maneira de contornar isso
alter igel
3
Correndo o risco de afirmar o óbvio, se você concorda em colocar apenas B*s no std::anyobjeto, e não em indicadores de classe derivados, isso resolve o problema com bastante facilidade.
277 Brian
2
Se não se encaixar no seu caso de uso, você pode explicar seu caso de uso?
Alan Birtles
1
Se todas myToolssão ferramentas, por que não apenas ter uma Toolclasse base e criar myToolsuma std::vector<std::unique_ptr<Tool>>?
Alan Birtles
1
@DanielMcLaury: " não há funcionalidade sobreposta entre serras e martelos " Então, por que eles estão na mesma matriz? Existe claramente alguma semelhança lógica entre eles, porque você parece querer colocá-los no mesmo lugar. Ou seja, não entendo por que myToolsexiste; por que você deseja colocar o que afirma ser objetos totalmente diferentes? iterar sobre eles para tentar se lembrar do que você colocou lá?
Nicol Bolas

Respostas:

2

Isso é inatingível. Só é possível remover um objeto std::anyusando exatamente o tipo que foi colocado dentro. Portanto, você deve conhecer o tipo para obter algo com isso.

Parece que std::anynão se encaixa no seu caso de uso.

eerorika
fonte
0

Adicionar uma classe base "Tool" com um atributo enum ToolType pode ajudar. Em seguida, usando o ToolType, você pode decidir sobre o elenco.

Pedro Ferreira
fonte
1
Isso pode funcionar, eu já vi isso. Mas é um cheiro de código enorme, eu não o recomendaria.
Mark Ransom
Sim, eu concordo com você, seria melhor repensar a arquitetura.
Pedro Ferreira