Полиморфный оператор в списке boost::any?

Предположим, у меня есть список типа list<boost::any>, в котором есть неизвестный тип. Теперь предположим, что я хочу применить некоторую операцию к полиморфным элементам списка. В этом случае рассмотрим оператор +. Предположим, что я знаю, что список всегда будет содержать однородный набор объектов, поддерживающих оператор+, и я хочу получить результат применения оператора+ («сумма» в одном смысле) между каждым элементом списка в новый boost:: любой. Что-то вроде этого:

boost::any sum(list<boost::any> lst) {
    // return lst[0]+lst[1]+lst[2] etc
}

Без перечисления всех возможных типов, которые могут поддерживать оператор +, есть ли способ сделать это? Я чрезвычайно открыт для сумасшедших идей.

(У меня действительно есть веская причина для этого... Я реализую интерпретатор)


person Derek Thurn    schedule 12.11.2010    source источник


Ответы (3)


Вместо этого вы можете использовать boost::variant, если знаете диапазон возможных типов в списке.

Я не понимаю, как вы можете сделать это без сетки operator+ функций для обработки всех возможных комбинаций содержащихся типов или обычного полиморфизма времени выполнения.

Интересно, какой конкретный тип вы хотите видеть в окончательном boost::any выводе?

Кстати, если вы реализуете интерпретатор, проверьте Boost .Spirit, который может пролить свет на вашу проблему с дизайном.

person Steve Townsend    schedule 12.11.2010
comment
Что касается окончательного вывода, я согласен с необходимостью приведения к правильному типу. Я просто хотел бы попытаться избежать этого здесь. - person Derek Thurn; 12.11.2010
comment
Итак, вам уже нужно преобразовать любой возможный тип в boost::any в вашу цель? Я бы хорошенько подумал над этой конструкцией. - person Steve Townsend; 12.11.2010

C++ сопоставляет функции (а операторы — это просто причудливые функции с дополнительным инфиксным синтаксисом) по их типам, а не по именам, во время компиляции. (Вместо того, чтобы проверять во время выполнения, поддерживают ли задействованные объекты запрошенную операцию.)
Единственным исключением, которое я могу придумать, являются виртуальные функции. Если бы типы были полиморфными, вы могли бы использовать любой обходной путь для отсутствующих мультиметодов (двойная диспетчеризация). Но так как это может быть что угодно, я не думаю, что вы можете это сделать.

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

(IME говорит, что это означает, что через очень короткое время кто-то приходит и доказывает, что я не прав.)

person sbi    schedule 12.11.2010

Нет. Ни с boost::any, ни с boost::variant (не соответствует вашему требованию «Без перечисления всех возможных типов, которые могут поддерживать оператор +»).

Что вам нужно сделать, это сделать свой собственный. Концепция boost::any довольно проста. Если вы посмотрите на документацию, у них есть ссылка на статью, объясняющую технику (в основном это идиома дескриптора/тела с полиморфизмом). Все, что вам нужно сделать, это решить, какой интерфейс должны иметь ваши различные объекты, и написать «любой» интерфейс, и он будет реализован соответственно. Что-то похожее на что-то вроде этого:

struct my_any
{
  template < typename T >
  my_any(T const& t) : pimpl(new impl<T>(t)) {}
  ...
  some_type get_some_type() const;
   ...
private:
  struct impl_base
  {
    ....
    virtual some_type get_some_type() const = 0;
  };
  template < typename T >
  struct impl : impl_base
  {
    some_type get_some_type() const { return t.get_some_type(); }
    impl(T const& t_var) : t(t_var) {}
    ....
  };
  boost::scoped_ptr<impl_base> pimpl;
};

some_type operator+ (my_any const& a, my_any const& b)
{
  return a.get_some_type() + b.get_some_type();
}

Трудно представить, что оператор + будет делать с универсальными типами, поэтому я придумал кое-что, что не имеет для меня особого смысла. Вам, конечно, нужно измениться в соответствии с вашими потребностями.

person Edward Strange    schedule 12.11.2010