2015-05-22 2 views
2

У меня есть два класса, я не могу изменить, оба имеют одни и те же элементы:Non-преобразующий, различные типы же члены

class Pose1 { 
    public: 
    double x,y; 
}; 
class Pose2 { 
    public: 
    double x,y; 
}; 

Одна часть кода использует Pose1 другой использует Pose2. Есть ли способ трансформировать их друг в друга? Теперь я должен писать все время

Pose1 p1(0.5, 0.5); 
Pose2 p2(p1.x,p2.y); 

Я знаю, что могу написать функцию преобразования, которая только что делает это один раз. Но у меня много разных типов с большим количеством аргументов.

Есть ли способ, что я могу сделать что-то вроде:

Pose2 p2 = static_cast<Pose2>(p1); 

Я не могу использовать функцию-член, потому что я не могу изменить этот код.

Спасибо!

+0

Я полагаю 'Pose2 p2 = * reinterpret_cast (&p1);' должны, по крайней мере, как правило, работают –

+1

@JerryCoffin I». m любопытно, будет ли это работать, разве это не нарушает правила [type aliasing] (http://en.cppreference.com/w/cpp/language/reinterpret_cast)? – BlackDwarf

+2

, представляя этот реинтерпрет, означает, что автор Классы Pose1 и Pose2 никогда не смогут безопасно поддерживать свой код еще раз, если он вводит тонкий баг в код потребителя. –

ответ

2

Нет, нет. Pose1 и Pose2 - это разные типы, не имеющие общих оснований. Тот факт, что они имеют одинаковые типы и имена участников, не имеет значения. Если вы хотите сделать их конвертируемыми друг в друга, вы должны явно предоставить эту поддержку.

Один из способов заключается в обеспечении внешней функции преобразования:

template <typename Pose, typename T> 
Pose toPose(const T& pose) { 
    return Pose{pose.x, pose.y}; 
} 

Pose2 pose2 = toPose<Pose2>(pose1); 

В качестве альтернативы, вы можете написать type_trait с помощью void_t чтобы увидеть, если что-то есть Pose или нет:

template <typename T, typename = void> 
struct is_pose : std::false_type { }; 

template <typename T> 
struct is_pose<T, void_t< 
       std::enable_if_t<std::is_same<decltype(T::x), double>::value>, 
       std::enable_if_t<std::is_same<decltype(T::y), double>::value>>> 
: std::true_type { }; 

А потом просто пишите «позеподобные» конструкторы для всех ваших поз:

class Pose2 { 
    template <typename T, typename = std::enable_if_t<is_pose<T>::value>> 
    Pose2(T&& pose_like) 
    : x(pose_like.x) 
    , y(pose_like.y) 
    { } 
}; 

Pose2 pose{pose1}; // works 
7

Попробуйте это:

template <class Dest, class Src> 
Dest pose_cast(const Src &src) 
{ 
    return Dest(src.x, src.y) ; 
} 

использование:

Pose1 p1 ; 
Pose2 p2 = pose_cast<Pose2, Pose1>(p1) 

Работы для обоих переходов.

+3

Вы можете пропустить «Src» в вызове: 'pose_ca st (p1); ' – Jarod42

0

Короткий ответ - нет.

, но вы можете сэкономить много работы, написав этот набор перегрузки функции и положить их в файл утилита заголовка:

inline Pose2 to_pose2(const Pose1& p1) { 
    return Pose2 { p1.x, p1.y }; 
} 

inline Pose2& to_pose2(Pose2& p2) { 
    return p2; 
} 

inline const Pose2& to_pose2(const Pose2& p2) { 
    return p2; 
} 

, которые затем могут быть использованы следующим образом:

void function_that_needs_a_pose2(const Pose2& p2); 

Pose1 p1; 
Pose2 p2; 

function_that_needs_a_pose2(to_pose2(p1)); 
function_that_needs_a_pose2(to_pose2(p2)); 

... или вы можете удерживать свои объекты Pose [n] в PoseHolder, что позволяет использовать неявные слепки:

inline Pose2 to_pose2(const Pose1& p1) { 
    return Pose2 { p1.x, p1.y }; 
} 

inline Pose1 to_pose1(const Pose2& p1) { 
    return Pose1 { p1.x, p1.y }; 
} 

struct PoseHolder { 
    PoseHolder(Pose1 p1) : _pose1 { std::move(p1) } {} 
    PoseHolder(Pose2 p2) : _pose2 { std::move(p2) } {} 


    operator const Pose1&() const { 
     if (!_pose1.is_initialized()) { 
      _pose1 = to_pose1(_pose2.value()); 
     } 
     return _pose1.value(); 
    } 

    operator const Pose2&() const { 
     if (!_pose2.is_initialized()) { 
      _pose2 = to_pose2(_pose1.value()); 
     } 
     return _pose2.value(); 
    } 

private: 
    mutable boost::optional<Pose1> _pose1; 
    mutable boost::optional<Pose2> _pose2; 
}; 
0

Нет, невозможно получить неявное преобразование, если вы не можете изменить хотя бы один из двух типов.

Некоторые могут предлагать отбрасывать один на другой посредством ссылки, но это все еще не подразумевается, поэтому вы можете написать функцию преобразования и не иметь неопределенного поведения.(Актерский нарушает строгие правила наложения спектров, и, таким образом, является UB.)

0

Я хотел бы сделать это:

class Pose1 { 
    public: 
    double x,y; 
}; 
/*class Pose2 { 
    public: 
    double x,y; 
};*/ 

typedef Pose1 Pose2; 

Я не понимаю, почему нет?

0

Макет памяти класса, как вы его указали, должен быть одинаковым.

Нет никакого неявного преобразования, но вы можете просто указать типы указателей.

Если у одного из ваших классов начинается виртуальная таблица, все ставки отключены, так как они зависят от компилятора, и вам требуется реальное явное преобразование.

Возможно, вы захотите обернуть конверсии в функции, чтобы она была аккуратной, и если вам нужно сделать больше работы позже, вы ее инкапсулируете.

0

другое решение, если вы не хотите, чтобы указать тип получателя в гипсе:

#include <iostream> 

class Pose1 { 
public: 
    double x,y; 
}; 
class Pose2 { 
public: 
    double x,y; 
}; 

namespace detail { 
    template<class T, class U> 
    struct PoseCaster { 

     operator U 
     () const 
     { 
      return U { _source.x, _source.y }; 
     } 

     operator 
     const T& 
     () const 
     { 
      return _source; 
     } 

     const T& _source; 
    }; 
} 

detail::PoseCaster<Pose1, Pose2> pose_cast(const Pose1& pose) { 
    return detail::PoseCaster<Pose1, Pose2> { pose }; 
} 

detail::PoseCaster<Pose2, Pose1> pose_cast(const Pose2& pose) { 
    return detail::PoseCaster<Pose2, Pose1> { pose }; 
} 

void funca(const Pose1&) { 
    std::cout << "funca" << std::endl; 
} 
void funcb(const Pose2&) { 
    std::cout << "funcb" << std::endl; 
} 

int main() 
{ 
    Pose1 a; 
    Pose2 b; 

    funca(pose_cast(a)); 
    funca(pose_cast(b)); 
    funcb(pose_cast(a)); 
    funcb(pose_cast(b)); 
} 
Смежные вопросы