2016-12-13 82 views
2

目标是编写一个通用模板函数,可以计算两点之间的距离(以p1和p2作为两个参数)。点可以通过多种方式来表示:通用编程中的C++类型验证

hopp::vector2<double> p0(0.0, 0.0); 
sf::Vector2<double> p1(0.0, 1.0); 
std::array<double, 2> p2 = { 1.0, 1.0 }; 
std::vector<double> p3 = { 1.0, 0.0 }; 
wxRealPoint p4(1.0, -1.0); 
QPointF p5(0.0, -1.0); 

和函数应该是这样的:

distance(p0,p1) 
distance(p1,p2) 
.... 

所以我的代码是这样:

#include <iostream> 
#include <math.h> 
#include <array> 
#include <vector> 
#include "hopp/vector2.hpp" 
#include "Qt/qpoint.h" 
#include "SFML/Vector2.hpp" 
#include "wxWidgets/gdicmn.h" 
template<class T1,class T2> auto distance2(T1 p1, T2 p2) 
{ 
    auto x1 = 0.0; 
    auto y1 = 0.0; 
    auto x2 = 0.0; 
    auto y2 = 0.0; 
    /* 
    * if p1 is a class. 
    */ 


    if (typeid(p1).name() == typeid(Point<int>).name() || 
     typeid(p1).name() == typeid(Point<double>).name()|| 
     typeid(p1).name() == typeid(Point<float>).name() || 
     typeid(p1).name() == typeid(hopp::vector2<double>).name() || 
     typeid(p1).name() == typeid(sf::Vector2<double>).name() || 
     typeid(p1).name() == typeid(wxRealPoint).name() || 
     typeid(p1).name() == typeid(QPointF).name() 
    ) { 
     x1 = p1.x; 
     y1 = p1.y; 
    } 
    /* 
    * if p1 is a array or vector. 
    */ 
    else if( typeid(p1).name() == typeid(std::array<double, 2>).name() 
    || 
      typeid(p1).name() == typeid(std::vector<double>).name() || 
      typeid(p1).name() == typeid(std::array<int>).name() || 
      typeid(p1).name() == typeid(std::vector<int>).name() || 
      typeid(p1).name() == typeid(std::array<float>).name() || 
      typeid(p1).name() == typeid(std::vector<float>).name() 

      ){ 
     x1 = p1[0]; 
     y1 = p1[1]; 
    } 

    if ( typeid(p2).name() == typeid(Point<int>).name() || 
     typeid(p2).name() == typeid(Point<double>).name()|| 
     typeid(p2).name() == typeid(Point<float>).name() || 
     typeid(p2).name() == typeid(hopp::vector2<double>).name() || 
     typeid(p2).name() == typeid(sf::Vector2<double>).name() || 
     typeid(p2).name() == typeid(wxRealPoint).name() || 
     typeid(p2).name() == typeid(QPointF).name() 
) 
    { 
    x2 = p2.x; 
    y2 = p2.y; 
    } else if (typeid(p2).name() == typeid(std::array<double, 2>).name() 
     || 
      typeid(p2).name() == typeid(std::vector<double>).name() || 
      typeid(p2).name() == typeid(std::array<int>).name() || 
      typeid(p2).name() == typeid(std::vector<int>).name() || 
      typeid(p2).name() == typeid(std::array<float>).name() || 
      typeid(p2).name() == typeid(std::vector<float>).name() 

     ){ 
     x2 = p2[0]; 
     y2 = p2[1]; 
    } 


    auto diff_x = x1-x2; 
    auto diff_y = y1-y2; 

    return sqrt(pow(diff_x,2)+pow(diff_y,2)); 
} 

有很多错误,当编译和我认为使用'typeid'进行多种类型验证不是一个好主意。我应该如何处理这个问题?

+2

为什么模板函数不能让你重载它? – Borgleader

+1

我个人会写'get_points'函数。对于所有需要支持的类型它都会被重载,并处理如何从函数中的类型中提取数据的逻辑。然后在通用函数中,您只需调用get points来获取数据,然后计算距离。 – NathanOliver

回答

2

为了避免大量超载使用sfinae机制,例如如下(live demo):

#include <iostream> 
#include <math.h> 
#include <array> 
#include <vector> 

struct Point { 
    double x; 
    double y; 
}; 

template <class T> 
auto getX(T t) -> decltype(t.x) { 
    return t.x; 
} 

template <class T> 
auto getX(T t) -> decltype(t[0]) { 
    return t[0]; 
} 

template <class T> 
auto getY(T t) -> decltype(t.y) { 
    return t.y; 
} 

template <class T> 
auto getY(T t) -> decltype(t[1]) { 
    return t[1]; 
} 

template <class T1, class T2> 
auto distance(T1 p1, T2 p2) { 
    auto x1 = getX(p1); 
    auto x2 = getX(p2); 
    auto y1 = getY(p1); 
    auto y2 = getY(p2); 
    auto diff_x = x1-x2; 
    auto diff_y = y1-y2; 

    return sqrt(pow(diff_x,2)+pow(diff_y,2)); 
} 



int main() { 
    Point p1; 
    std::vector<double> p2 = {1, 2}; 
    std::cout << distance(p1, p2) << std::endl; 
} 

这应该只要独立工作的点类型作为类型没有x构件,并在同一时间重载operator[]

+0

非常感谢您的回答。我已经测试了代码,当x和y在某个点上公开时,它会很顺利。当x和y是私有的时候,只需使用decltype(t.getPrivateX())添加两个函数即可获得它们。 – wjxiz

1

你应该能够在模板函数重载函数结合用于提取x和y的值:

template<typename T1,typename T2> 
auto distance(T1 p1, T2 p2) 
{ 
    const auto x1 = getX(p1); 
    const auto y1 = getY(p1); 
    const auto x2 = getX(p2); 
    const auto y2 = getY(p2); 

    const auto diff_x = x1 - x2; 
    const auto diff_y = y1 - y2; 

    return sqrt(pow(diff_x, 2) + pow(diff_y, 2)); 
} 

auto getX(const std::vector<double>& v) 
{ 
    return v[0]; 
} 

auto getX(const Point<double>& v) 
{ 
    return v.x; 
} 

... 

减少重载函数,你可以使干将数返回的std ::元组:

template<typename T1,typename T2> 
auto distance(T1 p1, T2 p2) 
{ 
    const auto p1_pair = get_values(p1); 
    const auto p2_pair = get_values(p2); 

    const auto diff_x = std::get<0>(p1_pair) - std::get<0>(p2_pair); 
    const auto diff_y = std::get<1>(p1_pair) - std::get<1>(p2_pair); 

    return sqrt(pow(diff_x, 2) + pow(diff_y, 2)); 
} 

auto get_values(const std::vector<double>& v) 
{ 
    return std::make_tuple(v[0], v[1]); 
} 

auto get_values(const Point<double>& v) 
{ 
    return std::make_tuple(v.x, v.y); 
} 

...