我想将数字映射到类型。对于此示例,我将创建一个将sizeof()结果映射到带符号原始类型的函数。
我想知道在现代C ++中是否有更好的方法可以做下面的事情,那就是采用模板化的值并将其转换为类型。现在,这可以将大小转换为已知类型,但是我似乎无法在标准库中找到满足我需要的内容。我错过了什么吗?
如果没有,是否有更好的方法来执行此操作或清除此代码?例如,如果将来以某种方式最终我们拥有128位类型,那将不支持该类型。
#include <iostream>
#include <type_traits>
template <size_t S>
static constexpr auto sizeToType() {
static_assert(S == 1 or S == 2 or S == 4 or S == 8, "Bad type size");
if constexpr (S == 1)
return int8_t{};
else if constexpr (S == 2)
return int16_t{};
else if constexpr (S == 4)
return int32_t{};
else
return int64_t{};
}
int main() {
using MY_TYPE = decltype(sizeToType<2>());
MY_TYPE myType = MY_TYPE(0xFFFFFFFFFFFFFFFEUL);
std::cout << sizeof(MY_TYPE) << " bytes" << std::endl;
std::cout << "MY_TYPE(0xFFFFFFFFFFFFFFFEUL) = " << myType << std::endl;
}
输出(按预期):
2 bytes
MY_TYPE(0xFFFFFFFFFFFFFFFEUL) = -2
答案 0 :(得分:7)
我不会为此使用C ++ 17 if constexpr
,而是使用模板特殊化,因为它对我来说更具声明性。
以下内容:
template<size_t S> struct SizeToType {static_assert(S != S, "Wrong size"); };
template<> struct SizeToType<1> { using type = uint8_t; };
template<> struct SizeToType<2> { using type = uint16_t; };
template<> struct SizeToType<4> { using type = uint32_t; };
template<> struct SizeToType<8> { using type = uint64_t; };
template<size_t S>
using SizeToToTypeT = typename SizeToType<S>::type;
添加更多类型只会在此处添加更多专业化(单线)。
答案 1 :(得分:2)
不是一个很好的解决方案...但是只是为了好玩...
我提出了一个类型特征(使用辅助方法并用于选择内部类型),给定一个数字(字节数)和一个类型列表,请选择大于class FilterInserts(beam.DoFn):
"""
Filter data for inserts
"""
def process(self, element):
if element["action"] == "insert":
element['data']['data']['timestamp'] = element['timestamp']
return [{
'VD': element['data']['data']['VD'],
'pin': element['data']['data']['pin'],
'timestamp': element['data']['data']['timestamp'],
'other': element['data']['data']['other'],
'CDP': element['data']['data']['CDP'],
'dir': element['data']['data']['dir'],
'attr1' : element['data']['data']['attr1'],
'seo' : element['data']['data']['seo'],
'day' : element['data']['data']['day'],
'DP' : element['data']['data']['DP'],
'at' : element['data']['data']['at'],
}]
或等于(如果没有这样的类型,则为空)
sizeof()
现在还有另一个template <std::size_t, typename, typename = std::true_type>
struct sizeTypeH;
template <std::size_t Dim>
struct sizeTypeH<Dim, std::tuple<>, std::true_type>
{ }; // no type found
template <std::size_t Dim, typename T0, typename ... Ts>
struct sizeTypeH<Dim, std::tuple<T0, Ts...>,
std::integral_constant<bool, (sizeof(T0) >= Dim)>>
{ using type = T0; };
template <std::size_t Dim, typename T0, typename ... Ts>
struct sizeTypeH<Dim, std::tuple<T0, Ts...>,
std::integral_constant<bool, (sizeof(T0) < Dim)>>
: public sizeTypeH<Dim, std::tuple<Ts...>>
{ };
template <std::size_t Dim, typename ... Ts>
struct sizeType : public sizeTypeH<Dim, std::tuple<Ts...>>
{ };
template <std::size_t Dim, typename ... Ts>
using sizeType_t = typename sizeType<Dim, Ts...>::type;
,它接收一个整数,并使用using
类型的有序列表将此类型特征称为
intX_t
在我的平台上,我已验证以下template <std::size_t Dim>
using intType_t = sizeType_t<Dim, std::int8_t, std::int16_t, std::int32_t,
std::int64_t>;
。
static_assert()
如果明天要引入 using t8 = intType_t<1u>;
using t16 = intType_t<2u>;
using t32 = intType_t<4u>;
using t64 = intType_t<8u>;
static_assert( std::is_same<t8, std::int8_t>{}, "!" );
static_assert( std::is_same<t16, std::int16_t>{}, "!" );
static_assert( std::is_same<t32, std::int32_t>{}, "!" );
static_assert( std::is_same<t64, std::int64_t>{}, "!" );
,则只需在int128_t
intType_t
定义中添加它即可。
请注意:没有保证满足前面的using
。
首先,因为标准保证一个字节至少为8位;但可以超过8位。如果一个字节是16位,则来自
static_assert()
您会得到 32 位的类型。
第二,因为using t16 = intType_t<2u>;
类型是可选的。