Gibt es eine Möglichkeit, ein std :: any, das einen abgeleiteten Zeiger enthält, in einen Basiszeiger umzuwandeln, ohne den abgeleiteten Typ zu kennen?


8

Angenommen, ich habe ein std::anyObjekt, das möglicherweise einen Zeiger auf eine abgeleitete Klasse einer bestimmten Basisklasse enthält oder nicht B. Kann ich auf irgendeine Weise etwas tun, das:

  1. Gibt a zurück B *, wenn das std::anyObjekt etwas enthält, das in B *oder konvertierbar ist
  2. Wirft eine Ausnahme, wenn nicht?

Es scheint so , dynamic_castund stellen std::any_castjeweils eine Hälfte dieser Funktionalität, aber ich sehe keine Möglichkeit , die beiden zusammen zu stellen.

Ich bin mir bewusst, dass ich diese Arbeit auf verschiedene Arten machen kann, bei denen jeder konvertierbare Typ explizit aufgelistet wird B *, aber das ist die Mutter aller DRY-Verstöße.


Anwendungsbeispiel:

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

Ich möchte keinen Haufen Boilerplate-Code einfügen, der jede existierende Säge auflistet, nur damit ich mir eine Säge schnappen kann - jede Saw -, in der ich sie verwenden kann Factory1.


1
Können Sie erklären, warum Sie std::anydies verwenden müssen und was Sie insgesamt zu lösen versuchen? Das klingt nach einem sehr unangenehmen Problem und es gibt wahrscheinlich einen besseren Weg, es zu
umgehen

3
Wenn Sie damit einverstanden sind, nur B*s in das std::anyObjekt und keine abgeleiteten Klassenzeiger einzufügen, ist das Problem recht einfach zu lösen.
Brian

2
Wenn es nicht zu Ihrem Anwendungsfall passt, können Sie dann Ihren Anwendungsfall erklären?
Alan Birtles

1
Wenn alle myToolsTools sind, warum nicht einfach eine ToolBasisklasse haben und myToolseine std::vector<std::unique_ptr<Tool>>erstellen?
Alan Birtles

1
@ DanielMcLaury: " Es gibt keine überlappenden Funktionen zwischen Sägen und Hämmern. " Warum befinden sie sich dann im selben Array? Es gibt eindeutig eine logische Gemeinsamkeit zwischen ihnen, weil Sie sie anscheinend an derselben Stelle festhalten möchten. Das heißt, ich verstehe nicht, warum es myToolsexistiert; Warum möchten Sie das, was Sie für völlig unterschiedliche Objekte halten, in das Objekt einfügen und es dann wiederholen, um sich daran zu erinnern, was Sie dort abgelegt haben?
Nicol Bolas

Antworten:


2

Das ist unerreichbar. Es ist nur möglich, ein Objekt herauszuholen, std::anyindem genau der Typ verwendet wird, der darin platziert wurde. Sie müssen also den Typ kennen, um etwas daraus zu machen.

Es scheint, dass std::anydas nicht zu Ihrem Anwendungsfall passt.


0

Das Hinzufügen einer Basisklasse "Tool" mit einem enum ToolType-Attribut kann hilfreich sein. Dann können Sie mit dem ToolType die Besetzung festlegen.


1
Das kann funktionieren, ich habe es gesehen. Aber es ist ein riesiger Code-Geruch, ich würde es nicht empfehlen.
Mark Ransom

Ja, ich stimme Ihnen zu, es wäre besser, die Architektur zu überdenken.
Pedro Ferreira
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.