2016-12-13 8 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가 한 점에서 public 일 때 잘된다. x와 y가 private 인 경우, 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; 
} 

... 

당신이 게터 만들 수있는 오버로드 기능의 수를 줄이려는 표준 : : 튜플을 반환 :

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

...