однако я не уверен, как переписать конструктор так, чтобы он вел себя как фабрика псевдоконструкторов.
Не конструктор: вы должны написать собственное руководство по выводам.
Что-то следующее
template <typename T1, typename T2>
Point(T1, T2) -> Point<promoted_type<T1, T2>>;
Ниже приведен полный пример компиляции
#include <type_traits>
template <typename... Ts>
struct promoted_type_wrap;
template <typename T>
struct promoted_type_wrap<T>
{ using type = T; };
template <typename T, typename U, typename... Ts>
struct promoted_type_wrap<T, U, Ts...>
{ using type = typename promoted_type_wrap<std::conditional_t<
(sizeof(U) <= sizeof(T)), T, U >, Ts... >::type; };
template <typename... Ts>
using promoted_type = typename promoted_type_wrap<Ts...>::type;
template <typename dtype>
class Point
{
protected:
dtype x, y;
public:
template <typename T1, typename T2>
constexpr Point (T1 const & a, T2 const & b) : x(a), y(b)
{ }
};
template <typename T1, typename T2>
Point(T1, T2) -> Point<promoted_type<T1, T2>>;
int main ()
{
constexpr auto z = Point(1, 2.0); // now Point<double>
constexpr auto w = Point(1.0, 2); // again Point<double>
static_assert( std::is_same_v<decltype(z), Point<double> const> );
static_assert( std::is_same_v<decltype(w), Point<double> const> );
}
Не по теме : я не думаю, что это хорошоИдея - выбрать «продвигаемый тип» в соответствии с размером типа, как в вашем
template <typename T, typename U, typename... Ts>
struct promoted_type_wrap<T, U, Ts...>
{ using type = typename promoted_type_wrap<std::conditional_t<
(sizeof(U) <= sizeof(T)), T, U >, Ts... >::type; };
Даже игнорируя другие проблемы, которые возникают, если у вас разные типы одинакового размера, выбранный тип является первым.
Например, в моей платформе g ++ и clang ++ имеют sizeof(long) == sizeof(float)
, поэтому мы получаем
constexpr auto z = Point(1l, 2.0); // <-- deduced as Point<long>
constexpr auto w = Point(1.0, 2l); // <-- deduced as Point<double>
static_assert( std::is_same_v<decltype(z), Point<long> const> );
static_assert( std::is_same_v<decltype(w), Point<double> const> );
Я предлагаю использовать что-то, что выбирает «предпочтительный тип» независимо отпорядок типов.
Мне кажется, что вы должны использовать std::common_type
следующим образом
#include <type_traits>
template <typename dtype>
class Point
{
protected:
dtype x, y;
public:
template <typename T1, typename T2>
constexpr Point (T1 const & a, T2 const & b) : x(a), y(b)
{ }
};
template <typename T1, typename T2>
Point(T1, T2) -> Point<std::common_type_t<T1, T2>>;
int main ()
{
constexpr auto z = Point(1l, 2.0); // <-- deduced as Point<double>
constexpr auto w = Point(1.0, 2l); // <-- deduced as Point<double>
static_assert( std::is_same_v<decltype(z), Point<double> const> );
static_assert( std::is_same_v<decltype(w), Point<double> const> );
}