Как ввести множество точек элегантно - PullRequest
1 голос
/ 30 ноября 2011

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

Так что я хотел бы иметь возможность вызвать следующий псевдокод

template<int dimenension> //the dimension of each of the points
struct set_of_points
{
  void insert(Iterator first_point, Iterator last_point);
}

из любого из следующих,

struct set_of_points<2> s;
double points1[3][2] = {
  {1,2},
  {2,3},
  {4,5}
};
s.insert(points1, points1+3);

double p1[2] = {1,2}, p2[2] = {2,3}, p3[2] = {4,5};
double* points2[3] = {p1,p2,p3};
s.insert(points2, points2+3);

std::vector<double*> points3;
points3[0] = p1; points3[1] = p2; points3[2] = p3;
s.insert(points3.begin(), points3.end())

и я мог бы добавить vector<vector<double> > и vector< boost::array<double,2> > к этому списку тоже.

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

#include<iostream>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_array.hpp>
#include <boost/type_traits/is_pointer.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/or.hpp>

template<int dimenension> //the dimension of each of the points
struct set_of_points
{
  //  The coordinates of each point are represented as an array or a set of pointers,
  //   And each point is in an array.
  template<typename PointsItr>
  void
  insert(PointsItr P_begin, PointsItr P_end,
     typename boost::enable_if<  //enable if
       typename boost::mpl::and_<  
         boost::is_pointer< PointsItr >, //The set of points is a pointer, AND
         typename boost::mpl::or_< //either
         boost::is_array<typename boost::remove_pointer< PointsItr >::type >, //The points are an array
           boost::is_pointer<typename boost::remove_pointer< PointsItr >::type > //or are pointers
          >::type  //close or
         >::type //close and
       >::type* dummy = 0)
  {
    std::cout<<"inserted pointer of (pointers OR array)"<<std::endl;
  }

};

int
main  (int ac, char **av)
{
  struct set_of_points<2> s;
  double points1[3][2] = {
    {1,2},
    {2,3},
    {4,5}
  };
  s.insert(points1, points1+3);

  double p1[2] = {1,2}, p2[2] = {2,3}, p3[2] = {4,5};
  double* points2[3] = {p1,p2,p3};
  s.insert(points2, points2+3);

}

ЮК. Есть ли приемлемый способ сделать это? Если нет, есть ли способ как-то убрать шум шаблона в библиотеку, чтобы мне не приходилось писать такой код для каждого контейнера, который я пишу.

Ответы [ 2 ]

0 голосов
/ 30 ноября 2011

Не существует стандартного способа сделать то, что вы просите, потому что если двойное * представляет точку (как в points2, points3), вы не знаете, насколько велик массив. Если, конечно, вы не доверяете пользователю вашей библиотеки задавать правильный размер и не вызывать ошибку (не делайте этого :-)).

Однако, если вы хотите, чтобы вектор, двойной массив в стиле c или любой контейнер значений типа double представляли точку, рассмотрите возможность использования BOOST_FOREACH (или циклов foreach в C ++ 11):

template <typename T>
Point MakePoint(const T& pointData)
{
    Point p;
    BOOST_FOREACH(double& x, pointData)
    {
        // check p isn't full
        p.Add(x);
    }

    return p;
}

(Не беспокойтесь о причудливых функциях enable_if, BOOST_FOREACH или c ++ 11 foreach обеспечит, чтобы T был контейнером типа double).

0 голосов
/ 30 ноября 2011

Хорошо, не могу найти элегантный способ сделать это.

Вот решение, которое я получил до сих пор, похоже, оно охватывает большинство баз:

#include<iostream>

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_array.hpp>
#include <boost/type_traits/is_pointer.hpp>
#include <boost/type_traits/is_class.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/or.hpp>
#include <boost/array.hpp>

#include <vector>


template<int dimenension> //the dimension of each of the points
struct set_of_points
{
  //  The coordinates of each point are represented as an array or a set of pointers,
  //   And each point is in an array.
  template<typename PointsItr>
  void
  insert(PointsItr P_begin, PointsItr P_end,
     typename boost::enable_if<  //enable if
       typename boost::mpl::and_<  
         boost::is_pointer< PointsItr >, //The set of points is a pointer, AND
         typename boost::mpl::or_< //either
         boost::is_array<typename boost::remove_pointer< PointsItr >::type >, //The points are an array
           boost::is_pointer<typename boost::remove_pointer< PointsItr >::type > //or are pointers
              >::type  //close or
         >::type //close and
       >::type* dummy = 0)
  {
    //get the type of the array
    std::cout<<"inserted pointer of (pointers OR array)"<<std::endl;
  }

  //  The coordinates of each point are represented as an array or a set of pointers,
  //   And each point is in a container.
  template<typename PointsItr>
  void
  insert(PointsItr P_begin, PointsItr P_end,
     typename boost::enable_if<  //enable if
       typename boost::mpl::and_<  
         boost::is_pointer< PointsItr >, //The set of points is a pointer, AND
         boost::is_class<typename boost::remove_pointer< PointsItr >::type> //The points are wrapped in a class, assume has a begin and end method
         >::type //close and
       >::type* dummy = 0)
  {
    //get the type of the array
    std::cout<<"inserted pointer of container"<<std::endl;
  }

  //  The coordinates of each point are represented as a class,
  //   And each point is an array or pointer
  template<typename PointsItr>
  void
  insert(PointsItr P_begin, PointsItr P_end,
     typename boost::enable_if<  //enable if
       typename boost::mpl::and_<  
         boost::is_class< PointsItr >, //The set of points is a class, AND
         typename boost::mpl::or_< //either
           boost::is_array<typename PointsItr::value_type >, //The points are an array
           boost::is_pointer<typename PointsItr::value_type> //or are pointers
           >::type  //close or
         >::type //close and
       >::type* dummy = 0)
  {
    //get the type of the array
    std::cout<<"inserted container of pointers"<<std::endl;
  }

  //  The coordinates of each point are represented as a class,
  //   And each point is a class
  template<typename PointsItr>
  void
  insert(PointsItr P_begin, PointsItr P_end,
     typename boost::enable_if<  //enable if
       typename boost::mpl::and_<  
         boost::is_class< PointsItr >, //The set of points is a class, AND
           boost::is_class<typename PointsItr::value_type > //The points are a class
         >::type //close and
       >::type* dummy = 0)
  {
    //get the type of the array
    std::cout<<"inserted container of containers"<<std::endl;
  }
};

int
main  (int ac, char **av)
{
  struct set_of_points<2> s;
  double points1[3][2] = {
    {1,2},
    {2,3},
    {4,5}
  };
  s.insert(points1, points1+3);

  double p1[2] = {1,2}, p2[2] = {2,3}, p3[2] = {4,5};
  double* points2[3] = {p1,p2,p3};
  s.insert(points2, points2+3);

  boost::array<double,2> p4,p5,p6;
  p4[0] = 1.0; p4[1] = 2.0;
  p5[0] = 1.0; p5[1] = 2.0;
  p6[0] = 1.0; p6[1] = 2.0;
  boost::array<double,2> points3[3] = {p4,p5,p6};
  s.insert(points3, points3+3);

  std::vector<double*> points4(3);
  points4[0]=p1; points4[1]=p2; points4[2]=p3;
  s.insert(points4.begin(), points4.end());

  std::vector<boost::array<double,2> > points5(3);
  points5[0]=p4; points5[1]=p5; points5[2]=p6;

  s.insert(points5.begin(), points5.end());


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