Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 调用std::nexting_difference()时的隐式转换_C++_Stl - Fatal编程技术网

C++ 调用std::nexting_difference()时的隐式转换

C++ 调用std::nexting_difference()时的隐式转换,c++,stl,C++,Stl,我想得到向量中相邻点之间距离的向量: struct Point { double x, y, z; } vector<double> adjacent_distances( vector<Point> points ) { ... } 所以我就希望这个能起作用, vector<double> adjacent_distances( vector<Point> points ) { vector<double> d

我想得到向量中相邻点之间距离的向量:

struct Point { double x, y, z; } 

vector<double> adjacent_distances( vector<Point> points ) {
    ...
}
所以我就希望这个能起作用,

vector<double> adjacent_distances( vector<Point> points ) 
{
    vector<double> distances;

    std::adjacent_difference( points.begin(), points.end(), 
                        std::back_inserter(distances), 
                        ptr_fun( point_distance ) );
    return distances; 
}
不幸的是,这与工作原理不一致

因此,我必须将代码转换为

double magnitude( Point pt );
Point  difference( Point a, Point b ); // implements b-a

vector<double> adjacent_distances( vector<Point> points ) 
{
    vector<Point> differences;

    std::adjacent_difference( points.begin(), points.end(), 
                        std::back_inserter(differences), 
                        ptr_fun( point_difference ) ); 


    vector<double> distances;

    std::transform( differences.begin(), differences.end(),
                        std::back_inserter(distances), 
                        ptr_fun( magnitude ) );

    return distances; 
}
双幅(点pt);
点差(点a、点b);//工具b-a
矢量相邻距离(矢量点)
{
向量差异;
std::相邻_差异(points.begin(),points.end(),
标准:背面插入器(差异),
ptr_fun(点差异);
矢量距离;
std::transform(differences.begin(),differences.end(),
标准:背面插入器(距离),
ptr_fun(震级));
返回距离;
}
注意:必须删除
差异的第一个元素才能使函数正确运行,但为了简洁起见,我跳过了实现细节


问题:有没有一种方法可以隐式地实现一些转换,这样我就不必创建额外的向量,并使用不同
值类型的
输入迭代器和
输出迭代器实现对
相邻差异()的调用

是的,这可以做到,但并不容易。我认为这不值得努力,除非你真的需要避免复制

如果您确实想这样做,您可以尝试创建自己的迭代器,在
向量
上进行迭代,并在
周围创建一个包装器

迭代器类将取消对包装器类实例的引用。包装器类应该支持
操作符-
或距离函数,并且应该存储距离。然后,您应该实现一个隐式转换为
double
的运算符,当
相邻的
尝试将包装分配给
向量时,将调用该运算符

我没有时间详细说明,所以如果有什么不清楚的地方,我会稍后再查,或者其他人可以试着更好地解释。下面是一个这样做的包装器示例

 struct Foo { 
     Foo(double value) { d = value; } 
     operator double() { return d; } 
     double d; 
 };

 Foo sub(const Foo& a, const Foo& b) {
     return Foo(a.d - b.d);
 }

 vector<Foo> values = {1, 2, 3, 5, 8}; 
 vector<double> dist; 
 adjacent_difference(values.begin(), values.end(), back_inserter(dist), sub);

 // dist = {1, 1, 1, 2, 3}
struct Foo{
Foo(双值){d=value;}
运算符double(){return d;}
双d;
};
Foo sub(施工Foo&a、施工Foo&b){
返回Foo(a.d-b.d);
}
向量值={1,2,3,5,8};
向量距离;
相邻的插入器差异(values.begin()、values.end()、back\u inserter(dist)、sub);
//dist={1,1,1,2,3}

这可能有点脏,但您可以简单地添加

struct Point {
    double x,y,z;
    operator double() { return 0.0; }
};
或许

struct Point {
    double x,y,z;
    operator double() { return sqrt(x*x + y*y + z*z); } // or whatever metric you are using
};

效果是将第一个距离设置为0,或将第一个点距原点的距离设置为0。但是,我可以想象,您不想用一个相当任意的定义来污染
结构,以便将其转换为
double
——在这种情况下,包装器是一个更干净的解决方案。

因为您不需要
相邻差异
返回的第一个元素,正是这个问题,你可以编写自己的算法版本,跳过初始赋值:

template <class InputIterator, class OutputIterator, class BinaryOperation>
OutputIterator my_adjacent_difference(InputIterator first, InputIterator last,
                                      OutputIterator result,
                                      BinaryOperation binary_op)
{
  if (first != last)
  {
    InputIterator prev = first++; // To start
    while (first != last)
    {
      InputIterator val = first++;
      *result++ = binary_op(*val, *prev);
      prev = val;
    }
  }
  return result;
}
模板
输出迭代器my_Nexture_difference(先输入迭代器,后输入迭代器,
输出结果,
二进制操作(二进制操作)
{
如果(第一个!=最后一个)
{
InputIterator prev=first++;//开始
while(第一个!=最后一个)
{
输入计算器val=第一个++;
*结果++=二进制运算(*val,*prev);
prev=val;
}
}
返回结果;
}

这应该是可行的,尽管您会错过一些STL优化。

事实上,
相邻的
算法在逻辑上被破坏了(为什么元素的时间差应该是相同的?为什么第一个输出元素等于第一个元素,而不是得到比输入元素短一个项目的输出序列(更符合逻辑)

<> P>无论如何,我不理解为什么你用C++的函数方法来惩罚自己,在这里代码显然会写得更难、读起来更难、编译得更慢,而不是更快地执行。哦,我们不要谈论如果你输入的类型有任何错误,你将要面对的笑话错误信息。 什么是坏的部分

std::vector<double> distances;
for (int i=1,n=points.size(); i<n; i++)
    distances.push_back(magnitude(points[i] - points[i-1]));
以下是公认的解决方案(我修正了通过值传递点向量的问题)

/------------algtest.cpp-------------
#包括
#包括
#包括
#包括
#包括
使用std::vector;
使用std::ptr_fun;
结构点
{
双x,y;
点(双x,双y):x(x),y(y)
{
}
点运算符-(常量点和其他)常量
{
返回点(x-其他.x,y-其他.y);
}
};
双幅(常数点和a)
{
返回sqrt(a.x*a.x+a.y*a.y);
}
双点距离(常数点a、常数点b)
{
返回量(b-a);
}
矢量相邻距离(常数矢量和点){
if(points.empty())返回向量();
矢量距离(
1,点距离(*points.begin(),*points.begin());
std::transform(points.begin(),points.end()-1,
points.begin()+1,
标准:背面插入器(距离),
ptr_fun(点距离);
返回距离;
}
int main()
{
std::向量点;

对于(inti=0;i来说,这可能不是很整洁,但是在这个特定的例子中,
std::transform
使用2个输入序列可能满足此目的。 例如:

vector<double> adjacent_distances( vector<Point> points ) {
    if ( points.empty() ) return vector<double>();

    vector<double> distances(
      1, point_distance( *points.begin(), *points.begin() ) );

    std::transform( points.begin(), points.end() - 1,
                    points.begin() + 1,
                    std::back_inserter(distances), 
                    ptr_fun( point_distance ) );
    return distances; 
}
矢量相邻距离(矢量点){
if(points.empty())返回向量();
矢量距离(
1,点距离(*points.begin(),*points.begin());
std::transform(points.begin(),points.end()-1,
points.begin()+1,
标准:背面插入器(距离),
ptr_fun(点距离);
返回
std::vector<double> distances;
for (int i=1,n=points.size(); i<n; i++)
    distances.push_back(magnitude(points[i] - points[i-1]));
~/x$ time for i in {1..10}
>   do
>     g++ -Wall -O2 -o algtest algtest.cpp
>   done

real    0m2.001s
user    0m1.680s
sys 0m0.150s
~/x$ time ./algtest

real    0m1.121s
user    0m1.100s
sys 0m0.010s
~/x$ time for i in {1..10}
>   do
>     g++ -Wall -O2 -o algtest2 algtest2.cpp
>   done

real    0m1.651s
user    0m1.230s
sys 0m0.190s
~/x$ time ./algtest2

real    0m0.941s
user    0m0.930s
sys 0m0.000s
~/x$ ls -latr algtest*.cpp
-rw-r--r-- 1 agriffini agriffini  932 2011-11-25 21:44 algtest2.cpp
-rw-r--r-- 1 agriffini agriffini 1231 2011-11-25 21:45 algtest.cpp
~/x$ 
// ---------------- algtest.cpp -------------
#include <stdio.h>
#include <math.h>
#include <functional>
#include <algorithm>
#include <vector>

using std::vector;
using std::ptr_fun;

struct Point
{
    double x, y;
    Point(double x, double y) : x(x), y(y)
    {
    }

    Point operator-(const Point& other) const
    {
        return Point(x - other.x, y - other.y);
    }
};

double magnitude(const Point& a)
{
    return sqrt(a.x*a.x + a.y*a.y);
}

double point_distance(const Point& a, const Point& b)
{
    return magnitude(b - a);
}

vector<double> adjacent_distances( const vector<Point>& points ) {
    if ( points.empty() ) return vector<double>();

    vector<double> distances(
      1, point_distance( *points.begin(), *points.begin() ) );

    std::transform( points.begin(), points.end() - 1,
                    points.begin() + 1,
                    std::back_inserter(distances),
                    ptr_fun( point_distance ) );
    return distances;
}

int main()
{
    std::vector<Point> points;
    for (int i=0; i<1000; i++)
        points.push_back(Point(100*cos(i*2*3.141592654/1000),
                               100*sin(i*2*3.141592654/1000)));

    for (int i=0; i<100000; i++)
    {
        adjacent_distances(points);
    }

    return 0;
}
// ----------------------- algtest2.cpp -----------------------
#include <stdio.h>
#include <math.h>

#include <vector>

struct Point
{
    double x, y;
    Point(double x, double y) : x(x), y(y)
    {
    }

    Point operator-(const Point& other) const
    {
        return Point(x - other.x, y - other.y);
    }
};

double magnitude(const Point& a)
{
    return sqrt(a.x*a.x + a.y*a.y);
}

std::vector<double> adjacent_distances(const std::vector<Point>& points)
{
    std::vector<double> distances;
    if (points.size()) distances.reserve(points.size()-1);
    for (int i=1,n=points.size(); i<n; i++)
        distances.push_back(magnitude(points[i] - points[i-1]));
    return distances;
}

int main()
{
    std::vector<Point> points;
    for (int i=0; i<1000; i++)
        points.push_back(Point(100*cos(i*2*3.141592654/1000),
                               100*sin(i*2*3.141592654/1000)));

    for (int i=0; i<100000; i++)
    {
        adjacent_distances(points);
    }

    return 0;
}
vector<double> adjacent_distances( vector<Point> points ) {
    if ( points.empty() ) return vector<double>();

    vector<double> distances(
      1, point_distance( *points.begin(), *points.begin() ) );

    std::transform( points.begin(), points.end() - 1,
                    points.begin() + 1,
                    std::back_inserter(distances), 
                    ptr_fun( point_distance ) );
    return distances; 
}
#include <iostream>             /* Standard C++ cout, cerr */
#include <vector>               /* Standard C++ vector */
#include <algorithm>            /* Standard C++ transform */
#include <iterator>             /* Standard C++ back_inserter */
#include <cmath>                /* Standard C++ sqrt */
#include <stdexcept>            /* Standard C++ exception */
using namespace std;            /* Standard C++ namespace */

struct Point {double x, y, z;}; // I would define this differently.

int main(int, char*[])
{
    try {
        const Point     points[] = {{0, 0, 0}, {1, 0, 0}, {1, 0, 3}};
        vector<double>  distances;
        transform(points + 1, points + sizeof(points) / sizeof(Point),
            points, back_inserter(distances),
            [](const Point& p1, const Point& p2)
            {
                double  dx = p2.x - p1.x;
                double  dy = p2.y - p1.y;
                double  dz = p2.z - p1.z;
                return  sqrt(dx * dx + dy * dy + dz * dz);
            });
        copy(distances.begin(), distances.end(),
            ostream_iterator<double>(cout, "\n"));
    }
    catch(const exception& e) {
        cerr    << e.what() << endl;
        return  -1;
    }
    catch(...) {
        cerr    << "Unknown exception" << endl;
        return  -2;
    }
    return  0;
}
1
3