2016-12-13 12 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'. Он перегружен для всех типов, которые вы хотите поддержать, и вы обрабатываете логику того, как извлекать данные из типа функции. Затем в общей функции вы просто вызываете точки получения, чтобы получить данные, а затем вычислить расстояние. – 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

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

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; 
} 

... 

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

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

...