¿Hay alguna forma de convertir un std :: alguno que contenga un puntero derivado a un puntero base, sin conocer el tipo derivado?

8

Digamos que tengo un std::any objeto que puede o no contener un puntero a alguna clase derivada de una clase base dada B. ¿Hay alguna manera de hacer algo que:

  1. Devuelve a B *, si elstd::any objeto contiene algo convertible a B *, o
  2. ¿Lanza una excepción si no?

Parece que dynamic_cast y std::any_castcada una proporciona la mitad de esta funcionalidad, pero no veo ninguna manera de poner los dos juntos.

Soy consciente de que puedo hacer que esto funcione de varias maneras que implican enumerar explícitamente cada tipo de convertible a B * , pero esa es la madre de todas las violaciones DRY.


Caso de uso de muestra:

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);
}

No quiero incluir un montón de código repetitivo que enumere cada tipo de sierra existente solo para poder agarrar una sierra, cualquiera Saw , para usar Factory1.

Daniel McLaury
fuente
1
¿Puede dar alguna explicación de por qué necesita usar std::anyesto y qué está tratando de resolver en general? Esto suena como un problema muy incómodo y probablemente haya una mejor forma de
solucionarlo
3
Con el riesgo de decir lo obvio, si acepta poner solo B*s en el std::anyobjeto, y no punteros de clase derivados, eso resuelve el problema con bastante facilidad.
Brian
2
Si no se ajusta a su caso de uso, ¿puede explicar su caso de uso?
Alan Birtles
1
Si todas myToolsson herramientas, ¿por qué no simplemente tener una Toolclase base y hacer myToolsuna std::vector<std::unique_ptr<Tool>>?
Alan Birtles
1
@DanielMcLaury: " no hay superposición de funciones entre sierras y martillos " ¿Entonces por qué están en la misma matriz? Claramente hay algo en común lógico entre ellos, porque parece querer pegarlos en el mismo lugar. Es decir, no entiendo por qué myToolsexiste; ¿por qué quieres poner lo que afirmas que son objetos completamente diferentes en él, luego iterar sobre ellos para tratar de recordar lo que pusiste allí?
Nicol Bolas

Respuestas:

2

Esto es inalcanzable. Solo es posible sacar un objeto std::anyusando exactamente el tipo que se puso dentro. Por lo tanto, debe conocer el tipo para sacar algo de él.

Parece que std::anyno se ajusta a su caso de uso.

eerorika
fuente
0

Agregar una clase base "Herramienta" que tenga un atributo enum ToolType puede ayudar. Luego, utilizando ToolType, puede decidir sobre el reparto.

Pedro Ferreira
fuente
1
Esto puede funcionar, lo he visto hecho. Pero es un gran olor a código, no lo recomendaría.
Mark Ransom el
Sí, estoy de acuerdo con usted, sería mejor repensar la arquitectura.
Pedro Ferreira