【问题标题】:How to input of an set of points elegantly如何优雅地输入一组点
【发布时间】:2011-11-30 11:05:01
【问题描述】:

我想将一组点输入到库中,其中该组的每个点都包含一组坐标。我希望输入对图书馆用户选择表示他们的数据的方式尽可能灵活。

所以我希望能够调用下面的伪代码

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&lt;vector&lt;double&gt; &gt;vector&lt; boost::array&lt;double,2&gt; &gt; 添加到该列表中。

我能想到的唯一方法是使用扩展的、丑陋的和手工制作的模板魔法。比如数组的指针和指针和指针都可以这样做。

#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);

}

哎呀。有没有一种可维护的方式来做到这一点?如果没有,有没有办法以某种方式将模板噪音整理到库中,这样我就不必为我编写的每个容器编写这样的代码。

【问题讨论】:

  • 听起来非常复杂,为什么不定义一些受限的point 类型(point2dpoint3d 等),然后简单地接受这些点的迭代器范围以插入到您的集合中?跨度>
  • @Nim,没想到会这么复杂。我希望我的库能够“正常工作”,而用户每次使用该库时都不必重新打包他们的数据。不过,您的解决方案更简单——至少这样我可以保证begin()end() 方法。
  • 冒着听起来像 80 年代冲浪者的风险,那是一些粗糙的代码花花公子。
  • 你为什么不写另一个模板类并传递你的坐标。并计算数组的长度并在其中编写两个函数 begin() 和 end()。?将更具可扩展性

标签: c++ templates generics containers


【解决方案1】:

好的,找不到这样做的优雅方法。

这是我目前得到的解决方案,它似乎涵盖了大多数基础:

#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());


}

【讨论】:

    【解决方案2】:

    没有标准的方法来做你所要求的,因为如果一个 double* 代表一个点(如在 points2、points3 中)你不知道数组有多大。除非您当然信任您的图书馆的用户提供正确的大小并且不会导致段错误(不要那样做:-))。

    但是,如果您想允许向量、c 样式的双精度数组或任何双精度容器表示一个点,请考虑使用 BOOST_FOREACH(或 C++11 foreach 循环):

    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 是双精度容器。)

    【讨论】:

      猜你喜欢
      • 2020-03-19
      • 2016-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多