如何在构造函数中应用算术类型提升
How to apply arithmetic type promotion within a constructor
假设,如果我正在创建一个点 class 并且我希望它根据参数推导出类型,我希望它将点 class 提升到最高参数。例如:
template <class dtype>
class Point;
...
auto x = Point(1, 1.0); // Point<double> specialized
auto y = Point(1.0, 1); // Point<double> specialized
我不确定如何在构造函数中实现这一点。我已经能够让它从一个调用显式专用构造函数的函数中推断出类型,而不是从构造函数本身推断出类型。
这是我目前的尝试:
#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<typename std::conditional<
(sizeof(U) <= sizeof(T)), T, U >::type, Ts... >::type;
};
template <typename... Ts>
using promoted_type = typename promoted_type_wrap<Ts...>::type;
template <typename T>
using same_type = typename promoted_type_wrap<T>::type;
template <class dtype>
class Point {
protected:
dtype x, y;
public:
constexpr Point(const dtype x, const same_type<dtype> y)
: x(x), y(y) {
}
};
template <class dtype, class etype>
constexpr auto make_Point(const dtype x, const etype y) {
return Point<promoted_type<dtype, etype>>(x, y);
}
void test() {
constexpr auto x = make_Point(1, 2.0); // Point<double> specialized
constexpr auto y = make_Point(1.0, 2); // Point<double> specialized
constexpr auto z = Point(1, 2.0); // Point<int> specialized
constexpr auto w = Point(1.0, 2); // Point<double> specialized
}
为什么 Point(1, 2.0)
被专门化为 Point<int>
是有道理的,因为第一个参数是 int
,它强制构造函数中的第二个参数是 int
;但是,我不确定如何重写构造函数以使其表现得像伪构造函数工厂。
however, I am unsure how to go about rewriting the constructor to behave like the pseudo-constructor factory.
不是构造函数:您必须编写自定义推导指南。
内容如下
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> );
}
题外话:我认为这不是一个好主意select "promoted type" 根据你[=19 中的类型大小=]
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; };
即使忽略其他问题,当您有相同大小的不同类型时,selected 类型是第一个。
例如,在我的平台中,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> );
我建议使用 select "preferred type" 独立于类型顺序的东西。
在我看来你应该使用 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> );
}
假设,如果我正在创建一个点 class 并且我希望它根据参数推导出类型,我希望它将点 class 提升到最高参数。例如:
template <class dtype>
class Point;
...
auto x = Point(1, 1.0); // Point<double> specialized
auto y = Point(1.0, 1); // Point<double> specialized
我不确定如何在构造函数中实现这一点。我已经能够让它从一个调用显式专用构造函数的函数中推断出类型,而不是从构造函数本身推断出类型。
这是我目前的尝试:
#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<typename std::conditional<
(sizeof(U) <= sizeof(T)), T, U >::type, Ts... >::type;
};
template <typename... Ts>
using promoted_type = typename promoted_type_wrap<Ts...>::type;
template <typename T>
using same_type = typename promoted_type_wrap<T>::type;
template <class dtype>
class Point {
protected:
dtype x, y;
public:
constexpr Point(const dtype x, const same_type<dtype> y)
: x(x), y(y) {
}
};
template <class dtype, class etype>
constexpr auto make_Point(const dtype x, const etype y) {
return Point<promoted_type<dtype, etype>>(x, y);
}
void test() {
constexpr auto x = make_Point(1, 2.0); // Point<double> specialized
constexpr auto y = make_Point(1.0, 2); // Point<double> specialized
constexpr auto z = Point(1, 2.0); // Point<int> specialized
constexpr auto w = Point(1.0, 2); // Point<double> specialized
}
为什么 Point(1, 2.0)
被专门化为 Point<int>
是有道理的,因为第一个参数是 int
,它强制构造函数中的第二个参数是 int
;但是,我不确定如何重写构造函数以使其表现得像伪构造函数工厂。
however, I am unsure how to go about rewriting the constructor to behave like the pseudo-constructor factory.
不是构造函数:您必须编写自定义推导指南。
内容如下
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> );
}
题外话:我认为这不是一个好主意select "promoted type" 根据你[=19 中的类型大小=]
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; };
即使忽略其他问题,当您有相同大小的不同类型时,selected 类型是第一个。
例如,在我的平台中,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> );
我建议使用 select "preferred type" 独立于类型顺序的东西。
在我看来你应该使用 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> );
}