0

我有许多 boost::any 的向量在这个向量中我需要对 std::vector 和 IContainer 类型的元素执行一些操作

class   IContainer
{
public:
  virtual ~IContainer(){}
  virtual const boost::any operator[](std::string) const = 0;
};

class   AContainer : public IContainer
{
  std::vector<int>      vect_;
  std::string name_;
public:
  AContainer() : vect_({0, 1, 2, 3, 4, 5}), name_("AContainer") {}
  virtual const boost::any operator[](std::string key) const
  {
    if (key == "str")
      return (name_);
    if (key == "vect")
      return (vect_);
    return nullptr;
  }
};

所以我做了以下功能(imo很丑)但谁工作正常

米是const std::vector<boost::any>&

for (const auto & elem : m)
    {
      try
        {
          std::vector<int> v = boost::any_cast<std::vector<int>>(elem);
          display(v);
        }
      catch(boost::bad_any_cast){}
      try
        {
          std::vector<IContainer*> v = boost::any_cast<std::vector<IContainer*>>(elem);
          display(v);
        }
      catch(boost::bad_any_cast){}
      try
        {
          AContainer v(boost::any_cast<AContainer>(elem));
          try
            {
              display(boost::any_cast<const std::vector<int>>(v["vect"]));
            }
          catch (boost::bad_any_cast){}
          try
            {
              std::cout << boost::any_cast<const std::string>(v["str"]) << std::endl;
            }
          catch (boost::bad_any_cast){}
          try
            {
              display(boost::any_cast<std::vector<int> >(v));
            }
          catch (boost::bad_any_cast) {}
        }
      catch(boost::bad_any_cast){}
    }

我尝试添加许多“ try{}try{}catch{}”但它不起作用

你有比我做的更好的解决方案吗

编辑

我尝试过 James Kanze、user1131467 和 Praetorian 的解决方案

所以这3个工作得很好,但是当我计算出执行时间时,user1131467的答案比另一个快一点。我现在必须找到一种解决方案来将每种类型存储在地图中,以避免所有这些 if/else

我还将看看 boost::variant

4

7 回答 7

7

使用指针形式any_cast更简洁,因为它使用指针的可空性:

for (const auto & elem : m)
    if (T1* p = any_cast<T1>(&elem))
    {
         do stuff with *p;
    }
    else if (T2* p = any_cast<T2>(&elem))
    {
         do stuff with *p;
    }
    else if (...)
    {
         ...
    }

这还具有每个案例进行一次演员阵容的优势。

于 2013-07-12T14:49:50.740 回答
5

您可以按照以下方式创建函数:

template <typename T>
bool 
isInstanceOf( boost::any const& object )
{
    return boost::any_cast<T>( &object ) != nullptr;
}

并使用它,用 if 来检查:

if ( isInstanceOf<std::vector<int>>( elem ) ) {
    display( boost::any_cast<std::vector<int>>( elem ) );
} else if ( isInstanceOf<std::vector<IContainer*>>( elem) ) {
    display( boost::any_cast<std::vector<IContainer*>>( elem) );
} 
//  ...
于 2013-07-12T14:50:01.663 回答
2

您可以编写自己的包装器any_cast来吞下异常。

template<typename T>
bool nothrow_any_cast( boost::any& source, T& out )
{
  try {
    out = boost::any_cast<T>( source );
  } catch ( boost::bad_any_cast const& ) {
    return false;
  }
  return true;
}

然后将其用作

std::vector<int> vect;
std::string str;

if( nothrow_any_cast(v["vect"], vect ) ) {
  // succeeded
} else if( nothrow_any_cast(v["str"], str ) ) {
  // succeeded
} ...

但是,如果您这样做,则默认构造所有类型,然后分配它们;所以即使它看起来更干净一点,它是否比你已经拥有的更好也是有争议的。

于 2013-07-12T14:53:19.600 回答
0

为什么不使用 boost::any_cast 的指针替代,它不会抛出任何东西,如果请求的类型与存储类型不匹配,它会返回 nullptr。如果你得到一个指针,你可以写一个显示的重载,它接受任何指针,检查它是否为空,如果指针不为空,则调用实际的显示函数。

template<typename T>
void display(T* p) { if ( p ) display(*p); }

使用上面的模板,只有 display 被称为正确的演员表。

for ( const auto& elem : m ) {
  display(boost::any_cast<int>(&elem));
  display(boost::any_cast<my_type>(&elem));
  ....
}
于 2013-07-12T16:36:36.043 回答
0

您可以将所有语句放在一个 try 块中:

try {
    // do all your stuff
}
catch (boost::bad_any_cast) {}
于 2013-07-12T14:38:24.820 回答
0

您在输入catch(...){}块时错过了添加任何指令。因此,当抛出异常时,您根本不处理它。

适当的处理通常包括跟踪错误级别并尝试解决错误状态(如果可能)。

由于在每个分支中都捕获了相同的异常,因此您可以将所有异常聚合到一个块中:

try{ ... }
catch(boost::bad_any_cast) { ...} 
于 2013-07-12T14:39:49.520 回答
0

没有一个答案是现在标准中的简单方法。

如果您使用“std::any”,那么您可以只使用“type()”函数来获取包含项目的 typeid。

于 2020-08-21T23:32:15.603 回答