有没有办法在不知道派生类型的情况下将包含派生指针的 std::any 转换为基指针?

Posted

技术标签:

【中文标题】有没有办法在不知道派生类型的情况下将包含派生指针的 std::any 转换为基指针?【英文标题】:Is there any way to cast a std::any containing a derived pointer to a base pointer, without knowing the derived type? 【发布时间】:2019-11-05 19:15:17 【问题描述】:

假设我有一个std::any 对象,它可能包含也可能不包含指向给定基类B 的某个派生类的指针。有什么办法可以做到:

    如果std::any 对象包含可转换为B * 的内容,则返回B *,或者 如果不抛出异常?

似乎dynamic_caststd::any_cast 各提供了一半的这种功能,但我看不出有任何将两者结合在一起的方法。

我知道我可以通过各种方式完成这项工作,包括显式枚举可转换为 B * 的每种类型,但这是所有 DRY 违规的根源。


示例用例:

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

我不想包含一堆样板代码,列出存在的每一种锯子,这样我就可以抓住锯子 -- 任何 Saw -- 用于@987654331 @。

【问题讨论】:

您能否解释一下为什么需要为此使用std::any,以及您要整体解决什么问题?这听起来像是一个非常尴尬的问题,可能有更好的解决方法 冒着明显的风险,如果您同意只将B*s 放入std::any 对象中,而不是派生类指针,那么很容易解决问题。 如果它不适合您的用例,那么您能解释一下您的用例吗? 如果所有的myTools 都是工具,为什么不只拥有一个Tool 基类并让myTools 成为std::vector&lt;std::unique_ptr&lt;Tool&gt;&gt; @DanielMcLaury: "锯子和锤子之间没有重叠的功能" 那么为什么它们在同一个数组中呢?它们之间显然存在 一些 逻辑共性,因为您似乎想将它们放在同一个地方。也就是说,我不明白为什么myTools 存在;为什么要将您声称完全不同的对象放入其中,然后遍历它们以尝试记住您放在那里的内容? 【参考方案1】:

这是无法实现的。只能使用放入其中的类型从std::any 中取出对象。因此,您必须知道类型才能从中获取任何信息。

std::any 似乎不适合您的用例。

【讨论】:

【参考方案2】:

我参加聚会迟到了,我自己只是偶然发现了这个问题,正在寻找答案。

这是我最终得出的结论。

我需要在std::any 中将wxMenuItem* 或指向某种控件的指针(均源自wxControl)传递给我的函数。我知道我是否有 wxMenuItem* 或基于标志的控件。所以暂时忽略 wxMenuItem* 。

由于我的代码只需要使用基类 wxControl 所具有的功能,(我想由于您的锤子共享一个公共基类,因此您只想做基本的锤子类型的东西),我...

static_cast&lt;wxControl*&gt;(myCombo*)

在调用点,并且

auto myPtr std::any_cast&lt;wxControl*&gt;(theAnyField);

在被调用点,瞧。

【讨论】:

我想这对于某些用例有一些缺点,但这对我来说也很完美。而且,如果你需要获取原始类型,只需 dynamic_cast any_cast 的结果!【参考方案3】:

添加具有枚举 ToolType 属性的基类“工具”会有所帮助。然后使用 ToolType 你可以决定演员表。

【讨论】:

这行得通,我已经看到了。但这是一个巨大的代码气味,我不会推荐它。 是的,我同意你的观点,最好重新考虑架构。

以上是关于有没有办法在不知道派生类型的情况下将包含派生指针的 std::any 转换为基指针?的主要内容,如果未能解决你的问题,请参考以下文章

指向包含可分配数组的派生类型的指针

Fortran 派生类型包含可从 C 访问的指针

使用基类指针查找派生类对象的大小

在不知道编码类型的情况下将 NSData 转换为 NSString

在不知道元素类型的情况下将项添加到列表中

如何从包含基类指针的容器中调用派生类函数(基于其类型)?