Могу ли я избежать всего этого кратного try/catch

У меня есть вектор много 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;
  }
};

Так что я сделал следующую функцию (я думаю, довольно уродливо), но кто работает правильно

м является 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{}"но это не работает

Есть ли у вас какие-либо решения лучше, чем то, что я сделал

редактировать

Я испробовал решения Джеймса Канзе, user1131467 и преторианца

Таким образом, эти 3 работают хорошо, но когда я вычисляю время выполнения, ответ user1131467 будет немного быстрее, чем другой. Теперь я должен найти решение для хранения каждого типа на карте, чтобы избежать всего этого, если / иначе

Я также посмотрю на Boost:: вариант

6 ответов

Решение

Используя указатель-форму 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 (...)
    {
         ...
    }

Это также имеет преимущество делать бросок один раз за случай.

Вы можете создать функцию в соответствии с:

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

и используйте его, чтобы проверить:

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

Вы могли бы написать свою собственную обертку вокруг 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
} ...

Однако, если вы сделаете это, вы по умолчанию создаете все типы, а затем назначаете их; так что даже если она выглядит немного чище, это спорно, является ли это лучше, чем то, что у вас уже есть.

Вы пропустили добавить любую инструкцию при вводе catch(...){} блок. Поэтому, когда выдается исключение, вы вообще не обрабатываете его.

Соответствующая обработка обычно включает в себя отслеживание уровня ошибки и попытки разрешить состояние ошибки (если это возможно).

Поскольку в каждой ветви вы ловите одно и то же исключение, вы можете объединить их все в один блок:

try{ ... }
catch(boost::bad_any_cast) { ...} 

Почему бы не использовать альтернативный указатель boost::any_cast, он ничего не выдает, он возвращает nullptr, если запрошенный тип не совпадает с типом хранилища. И если вы получите указатель обратно, вы можете просто написать перегрузку для отображения, которая принимает любой указатель, проверяет его на нулевое значение и вызывает фактическую функцию отображения, если указатель не равен нулю.

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

С шаблоном выше, только показ вызывается для правильного приведения.

for ( const auto& elem : m ) {
  display(boost::any_cast<int>(&elem));
  display(boost::any_cast<my_type>(&elem));
  ....
}

Вы можете поместить все операторы в один блок try:

try {
    // do all your stuff
}
catch (boost::bad_any_cast) {}

Ни один из ответов не идет тем простым путем, который сейчас предусмотрен стандартом.

Если вы используете "std::any", вы можете просто использовать функцию "type()" для получения typeid содержащего элемента.

Другие вопросы по тегам