Как справиться с избыточностью типов во внешних библиотеках? - PullRequest
1 голос
/ 16 июля 2009

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

Например, в колледже я написал кватернионные, оптимизированные 3-классные и оптимизированные матричные классы 4x4, которые мне нравятся, поскольку они эффективны, и я с ними хорошо знаком. Я также написал реализацию K-D Tree, которая зависит только от STL.

Наконец, я использую ITK для вычисления минимального собственного значения (и связанного собственного вектора) данной симметричной вещественной матрицы, среди прочего.

Со всеми этими библиотеками, содержащими свои собственные матрицы и векторные реализации, я обнаружил, что делаю много такого рода вещей:

FixedPointType closestPointCoords;
KdTree::HyperPoint target(3);
target[0] = transformedPoint[0];
target[1] = transformedPoint[1];
target[2] = transformedPoint[2];
KdTree::Neighbor result = FixedPointTree.FindNearestNeighbor(target);
minimumDistance = result.GetDistance();
closestPointCoords[0] = result.GetPoint().Get(0);
closestPointCoords[1] = result.GetPoint().Get(1);
closestPointCoords[2] = result.GetPoint().Get(2);

Очевидно, я мог бы написать функцию, которая выглядит примерно так:

FixedPointType ConvertHyperPointToFixedPointType(const KdTree::HyperPoint &p)
{
    FixedPointType fixedPoint;
    fixedPoint[0] = p[0];
    fixedPoint[1] = p[1];
    fixedPoint[2] = p[2];

    return fixedPoint;
 }

Я бы хотел избежать зависимости между библиотеками, выполнив что-то вроде этого:

class HyperPoint
{
    ...
    operator FixedPointType() 
    {
         // Same content as ConvertHyperPointToFixedPointType above
    }
    ...
};

Но мне интересно, придумал ли кто-нибудь более изящное решение этой проблемы.

Возможно, мне следует взять страницу из книги .NET и создать статический класс Convert?

Как вы справились с избыточностью типов в библиотеках и с необходимостью частого преобразования между различными типами?

Подходит ли здесь шаблон Adapter ?

UPDATE
После еще нескольких исследований я наткнулся на TypeConverter . Так что эта проблема выглядит так, как будто она решена в C #. Я все еще ищу чистый, эффективный и простой способ сделать это в C ++. Пока что я думаю о канонических типах или, может быть, просто обнаженных функциях ConvertHyperPointToFixedPointType.

ОБНОВЛЕНИЕ 2 После еще большего прочтения звучит так, будто канонический тип фактически будет действовать как прокладка. Смотрите эту бумагу для получения дополнительной информации.

Вот пример кода, иллюстрирующий мою склонность:

class VectorConverter
{
public:
    VectorConverter(const VectorImp1 &v1)
    {
        _data[0] = v1[0];
        _data[1] = v1[1];
        _data[2] = v1[2];
    }

    VectorConverter(const VectorImp2 &v2)
    {
        _data[0] = v2.Get(0);
        _data[1] = v2.Get(1);
        _data[2] = v2.Get(2);
    }

    operator VectorImp1()
    {
        return VectorImp1(_data[0], _data[1], _data[2]);
    }

    operator VectorImp2()
    {
        VectorImp2 v2;
        v2.Set(0, _data[0]);
        v2.Set(1, _data[1]);
        v2.Set(2, _data[2]);
        return v2;
    }

    // actual vector implementation goes here or a wrapper around an existing one
};

// example usage
VectorImp1 closestPointCoords, target;
// for the sake of illustration I included the cast, but you could implicitly cast
KdTree::Neighbor result = FixedPointTree.FindNearestNeighbor((VectorImp2)VectorConverter(target));
minimumDistance = result.GetDistance();
closestPointCoords = (VectorImp1)VectorConverter(result.GetPoint());

Спасибо за вашу помощь. Не стесняйтесь обновлять этот пост, если кто-то сталкивается с чем-то лучшим.

Ответы [ 2 ]

1 голос
/ 16 июля 2009

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

Если вы действительно хотите это сделать, вы можете создать интерфейс IMatrix и реализовать интерфейс для каждого типа адаптера.

Другим решением является создание канонического типа и создание переводчиков для этого типа в каждой версии Matrix.

Эти два способа эквивалентны в строках кода, но второй более интуитивно понятен.

1 голос
/ 16 июля 2009

CAVEAT: У меня сейчас нет компилятора, и я неожиданно не уверен насчет части SFINAE (не уверен, относится ли она к телу функции или только к типы параметров). Кто-нибудь, пожалуйста, исправьте это, если это не так.

В C ++ вы можете воспользоваться одинаковым синтаксисом разных классов для создания единого шаблона функции:

template <class ToType, class FromType>
ToType ConvertPoint(const FromType& FromValue)
{
  ToType ToValue;
  ToValue[0] = FromValue[0];
  ToValue[1] = FromValue[1];
  ToValue[2] = FromValue[2];

  return ToValue;
}

// If the version above failed, the compiler will try this one.
// This is called SFINAE
template <class ToType, class FromType>
ToType ConvertPoint(const FromType& FromValue)
{
  ToType ToValue;
  ToValue[0] = FromValue.Get(0);
  ToValue[1] = FromValue.Get(1);
  ToValue[2] = FromValue.Get(2);

  return ToValue;
}

// Usage:
KdTree::HyperPoint hyperPoint;
FixedPointType fixedPoint = ConvertPoint<FixedPointType>(hyperPoint);

Я думаю, вы можете сделать то же самое в C #, хотя я менее знаком с синтаксисом.

В тех случаях, когда ваши классы не совсем соответствуют одному и тому же синтаксическому соглашению, SFINAE поможет вам, предоставив вам несколько вариантов - если один из них окажется неудачным, компилятор выберет следующий и попробует с этим. Используя shims , вы можете ограничить число вариантов, предоставив одну универсальную функцию, которая использует соответствующим образом определенные прокладки для обоих наборов и получения каждой координаты для всех существующих классов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...