boost::операторы смешанной арифметики

на основе приведенного здесь примера http://www.boost.org/doc/libs/release/libs/utility/operators.htm#example я реализовал следующий производный класс boost::numeric::ublas::vector:

namespace Chebyshev
{
  template<typename T>
  class function_data : public boost::numeric::ublas::vector<T>,
                               boost::addable<function_data<T> >,
                               boost::subtractable<function_data<T> >,
                               boost::multipliable2<function_data<T>, T>,
                               boost::dividable2<function_data<T>, T>
  {
    public:
      char dataflag;
      function_data() : boost::numeric::ublas::vector<T>() {dataflag=0;} ///< The default empty constructor
      function_data(const boost::numeric::ublas::vector<T>& vec) : boost::numeric::ublas::vector<T>(vec) {dataflag=0;} ///< The copy constructor without a flag.
      function_data(const boost::numeric::ublas::vector<T>& vec, char flag) : boost::numeric::ublas::vector<T>(vec), dataflag(flag) {} ///< The copy constructor with a flag.
      ~function_data() {} ///< The destructor.
      function_data<T>& operator= (const boost::numeric::ublas::vector<T>& in) {boost::numeric::ublas::vector<T>::operator=(in); return *this;} ///< The assignment operator from a boost::numeric::ublas::vector<T>.
      function_data<T>& operator= (const function_data<T>& in) {boost::numeric::ublas::vector<T>::operator=(in); dataflag=in.dataflag; return *this;} ///< The assignment operator.
      function_data<T>& operator+= (const function_data<T>& in) {this->boost::numeric::ublas::vector<T>::operator+=(in); this->dataflag=this->dataflag; return *this;}
      function_data<T>& operator-= (const function_data<T>& in) {this->boost::numeric::ublas::vector<T>::operator-=(in); this->dataflag=this->dataflag; return *this;}
      function_data<T>& operator*= (T in) {this->boost::numeric::ublas::vector<T>::operator*=(in); this->dataflag=this->dataflag; return *this;}
      function_data<T>& operator/= (T in) {this->boost::numeric::ublas::vector<T>::operator/=(in); this->dataflag=this->dataflag; return *this;}
      friend std::ostream& operator<< (std::ostream& os, const function_data<T>& fd) {os << "[type " << fd.dataflag << "] " << static_cast<boost::numeric::ublas::vector<T> >(fd); return os;} ///< The << operator.
  };
}

Однако компиляция следующего фрагмента кода

int main( int argc, char ** argv)
{
  Chebyshev::function_data<std::complex<double> > u;
  /* some stuff putting values in u */
  std::cout << u*2 << std::endl;
  return 0;
}

выдает предупреждение «ISO C++ говорит, что они неоднозначны, хотя наихудшее преобразование для первого лучше, чем наихудшее преобразование для второго» и продолжает выдавать версию ublas vector_expression (с u приведенным как своего рода vector_expression) и мой версия (с 2 отлитой как const std::complex<double>&).

Я хотел бы иметь возможность использовать смешанную арифметику в своем классе, как в приведенном выше фрагменте кода, но объяснение на сайте boost::operators мне непонятно. Что мне нужно добавить или изменить в моем классе, чтобы разрешить это?

Кроме того, в этом примере в списке наследования каждый класс находится внутри последних > предыдущего класса. Я не вижу никакой разницы в выводе компилятора, пишу ли я так или так, как указано выше. Как правильно написать?

С уважением, Бретт.


person Brett Ryland    schedule 01.06.2011    source источник
comment
Должен ли class function_data наследовать boost::numeric::ublas::vector<T>? Не может ли он просто иметь член типа boost::numeric::ublas::vector<T>?   -  person yasouser    schedule 01.06.2011
comment
Я мог бы переписать код таким образом, но я бы предпочел работать с function_data<T>, как если бы это был boost::numeric::ublas::vector<T> с дополнительным флагом, указывающим тип (не тип данных ;-)) хранящихся в нем данных.   -  person Brett Ryland    schedule 01.06.2011
comment
@Brett: вы можете проверить эти вопросы в SO: 1) stackoverflow.com/questions/4353203/ 2) stackoverflow.com/questions/2034916/ и 3) stackoverflow.com/questions/679520/   -  person yasouser    schedule 01.06.2011
comment
@yasouser: Достаточно честно. Если я сделаю ...vector<T> членом function_data и реализую операторы, необходимые для сложения, вычитания, умножения2 и делимости2, будет ли это автоматически разрешать смешанную арифметику в моем классе function_data?   -  person Brett Ryland    schedule 01.06.2011
comment
@Brett: Код вашего примера должен компилироваться нормально, если вы правильно реализовали все операторы. class function_data<T> действует как оболочка для ...ublas::vector<T>.   -  person yasouser    schedule 01.06.2011
comment
@yasouser: Спасибо. Любая идея о >s в примере? Это просто выбор стиля форматирования или есть какая-то заметная разница в реализации?   -  person Brett Ryland    schedule 01.06.2011
comment
@Brett: Вы пытаетесь выполнять векторные арифметические операции, используя boost ublas?   -  person yasouser    schedule 02.06.2011
comment
@yasouser: Да. Я реализую набор инструментов для спектрально точных приближений функций, их градиентов и их интегралов в симплициальных областях с использованием многомерных полиномов Чебышева. Функции могут быть представлены либо их значениями, либо коэффициентами аппроксимирующих полиномов (используя FFTW для переключения между ними), но их невозможно отличить, просто взглянув на значения в векторе T›, поэтому мне нужен дополнительный флаг данных. Я хотел бы реализовать несколько арифметических операторов, учитывающих переменную dataflag и вызывающих соответствующий ublas routine.   -  person Brett Ryland    schedule 03.06.2011
comment
@Brett: Вы смотрели на vector_expressions‹› в boost ublas (boost.org/doc/libs/1_46_1/libs/numeric/ublas/doc/)?   -  person yasouser    schedule 03.06.2011
comment
@yasouser: я просмотрел их, но не вижу, как они здесь помогают (я не уверен, что достаточно хорошо понимаю, чем vector_expressions отличаются от векторов). В основном я использую переменную dataflag, чтобы упростить интерфейс для различных функций в панели инструментов и уменьшить возможности пользователя писать с ее помощью бессмысленный код.   -  person Brett Ryland    schedule 04.06.2011


Ответы (1)


В Boost uBLAS есть все операторы, необходимые для векторной арифметики. Вот пример программы, чтобы выделить его:

#include <iostream>

#include "boost/numeric/ublas/vector.hpp"
#include "boost/numeric/ublas/io.hpp"

using namespace boost::numeric::ublas;

int main()
{
  vector<int> v1(4);
  vector<int> v2(4);
  vector<int> v3(4);
  vector< std::complex<double> > v4(4);

  for (size_t i = 0; i < v1.size(); i++)
    v1(i) = (i + 1) * 3;
  for (size_t i = 0; i < v1.size(); i++)
    v2(i) = (i + 1) * 10;
  for (size_t i = 0; i < v4.size(); i++)
    v4(i) = std::complex<double>(v1(i), v2(i));

  std::cout << "v1: " << v1 << std::endl;
  std::cout << "v2: " << v2 << std::endl;
  std::cout << "v3 = v2 * 3: " << (v3 = v2 * 3) << std::endl;
  std::cout << "v4: " << v4 << std::endl;
  std::cout << "v1 + v2: " << v1 + v2 << std::endl;
  std::cout << "v1 - v2: " << v1 - v2 << std::endl;
  std::cout << "v1 * 3: " << v1 * 3 << std::endl;
  std::cout << "(v2 * 2) / 3: " << (v2 * 2) / 3 << std::endl;
  std::cout << "v4 * 3: " << v4 * 3 << std::endl;
  std::cout << "v4 + v4" << v4 + v4 << std::endl;

  std::cout << "element_prod(v1, v2)" << element_prod(v1, v2) << std::endl;
  std::cout << "element_div(v2, v1)" << element_div(v2, v1) << std::endl;

  return 0;
}

Вот результат, который я получил, когда скомпилировал и запустил с помощью g++ v4.1.2:

[ublas]$ g++ -o vector vector.cpp 
[ublas]$ ./vector 
v1: [4](3,6,9,12)
v2: [4](10,20,30,40)
v3 = v2 * 3: [4](30,60,90,120)
v4: [4]((3,10),(6,20),(9,30),(12,40))
v1 + v2: [4](13,26,39,52)
v1 - v2: [4](-7,-14,-21,-28)
v1 * 3: [4](9,18,27,36)
(v2 * 2) / 3: [4](6,13,20,26)
v4 * 3: [4]((9,30),(18,60),(27,90),(36,120))
v4 + v4[4]((6,20),(12,40),(18,60),(24,80))
element_prod(v1, v2)[4](30,120,270,480)
element_div(v2, v1)[4](3,3,3,3)
person yasouser    schedule 04.06.2011
comment
Я знаком с векторами ublas (не vector_expressions), и именно эти операторы (плюс element_prod и element_div) я хочу использовать для базовых операций. Пример: пусть ublas::vector<T> u и char flag будут членами function_data, а a и b будут экземплярами function_data с a.flag=v и b.flag=c (две функции, представленные как значения функций и коэффициенты соответственно). Предположим, я пишу a*=b. *= должен обнаружить, что a и b имеют разные флаги, преобразовать b в b.flag=v, применив БПФ к b.u, а затем вызвать a.u=element_prod(a.u,b.u). - person Brett Ryland; 04.06.2011
comment
Похоже, вы хотите, чтобы operator *= делал больше, чем просто умножал. UBLAS operator *= позволяет только умножать вектор на скаляр. Я думаю, что ваше требование выполнить БПФ для одного из ваших операндов перед выполнением element_prod() нарушает семантику operator *=. Кроме того, какова цель члена flag в function_data? - person yasouser; 04.06.2011
comment
вектора ublas внутренне используют vector_expressions. Операторные методы вектора ublas используют vector_expression. Также я думаю вам будет полезна следующая ссылка: boost.org/doc/libs/1_45_0/libs/numeric/ublas/doc/ - person yasouser; 04.06.2011
comment
Вы, кажется, упускаете из виду то, что я пытаюсь сделать. Операторы класса function_data предназначены для работы с математическими функциями, например. f(x), g(x). Они представлены в виде векторов ublas, содержащих либо выборочные значения, либо коэффициенты, обозначенные flag. Для выполнения некоторых операций, таких как (f*g)(x), f(x) и g(x), они должны быть представлены одинаково, поэтому операторы function_data должны принимать некоторые решения/проверки работоспособности на основе flag и вызывать функцию соответствующие операции ублас. - person Brett Ryland; 05.06.2011
comment
Ваш комментарий вверху со ссылками на 3 SO-вопроса убедил меня использовать вектор как член function_data вместо использования наследования, поэтому мой вопрос касается > > > > в цепочке наследования в примере boost::operators. т.е. должно быть class point : boost::addable<point<T>, boost::subtractable<point<T>, ... > > или class point : boost::addable<point<T> >, boost::subtractable<point<T> >, ...? Оба, кажется, компилируются, но есть ли разница в функциональности между этими двумя случаями? - person Brett Ryland; 05.06.2011