C++:在编译时确定给定整数类型的整数转换等级?
Posted
技术标签:
【中文标题】C++:在编译时确定给定整数类型的整数转换等级?【英文标题】:C++: Determine the integral conversion rank of a given integral type at compile time? 【发布时间】:2016-06-08 20:52:15 【问题描述】:在我正在进行的一个项目中,我有一个可以存储各种类型数字的数据结构,并且需要保证不会意外丢失精度/信息。
因为标准 C++ 允许隐式发生一些有损转换,所以我创建了一个类型特征,用于确定我将允许哪些转换并禁止我不喜欢使用 SFINAE 的转换。
我意识到我是如何做到这一点的存在一个微妙的问题。
这是一段代码摘录:
// If it is between two floating point types, no truncation is allowed.
template <typename A, typename B>
struct safe_numeric<A,
B,
typename std::enable_if<(std::is_floating_point<A>::value &&
std::is_floating_point<B>::value)>::type>
static constexpr bool value = sizeof(A) >= sizeof(B);
;
本意是,float
可以提升为double
或long double
,double
可以提升为long double,但不能变小。
但是,在这里使用sizeof
是不好的,因为在sizeof(double) == sizeof(float)
所在的机器上,根据此模板将double
转换为float
是合法的。这将使我的程序不可移植——开发人员可以编写在他们的机器上编译和运行良好的代码,事实上,不会丢失精度。但是在其他一些机器上,它可能只是无法编译并抱怨不安全的转换。
例如,我真正想要的是获得[4.13] [conv.rank]
中标准所述的conversion rank
。我想对浮点和整数类型都这样做。
例如,我可以自己滚动:
template <typename T>
struct conversion_rank;
template <>
struct conversion_rank<float>
static constexpr std::size_t value = 0;
;
template <>
struct conversion_rank<double>
static constexpr std::size_t value = 1;
;
template <>
struct conversion_rank<long double>
static constexpr std::size_t value = 2;
;
并使用该元函数而不是sizeof
。
如果我想对整数类型执行此操作...还有很多。
还有一个问题是整数类型不需要存在,所以我可能想尝试检测这种情况,以便 conversion_rank
模板能够编译。
有没有更好/标准的方法来解决这个问题?我在标准库中没有找到“conversion_rank”元函数,我猜该标准实际上并没有给出数值,它只是指定了“更高”和“更低”。但也许boost
/其他一些不那么费力且不依赖sizeof
的策略?
【问题讨论】:
既然你本质上想要阻止变窄,只需 SFINAE 对Deststd::declval<Source>()
的良构性?
这正是我希望得到的答案,谢谢!
其实我收回了。如果你想要完全的可移植性,你必须用等级来写这个。
将允许 long long
到 long
在 LP64 上。
@T.C. long long
到 long
的转换是标准允许的,还是编译器中的错误?
我很确定给定两个整数类型T1
和T2
具有相同的大小但转换排名低于int
,无法确定哪个具有更大的排名使用通常的 TMP 技术,无需对其进行硬编码。因此,如果您想要 100% 的可移植性,您要么必须自己进行硬编码,要么找人为您完成 :)
【参考方案1】:
我开源了the component,我最终为此使用了它。
我用来做排名的代码是这样的(见here):
enum class numeric_class : char integer, character, wide_char, boolean, floating ;
template <typename T, typename ENABLE = void>
struct classify_numeric;
template <typename T>
struct classify_numeric<T, typename std::enable_if<std::is_integral<T>::value>::type>
static constexpr numeric_class value = numeric_class::integer;
;
#define CLASSIFY(T, C) \
template <> \
struct classify_numeric<T, void> \
static constexpr numeric_class value = numeric_class::C; \
CLASSIFY(char, character);
CLASSIFY(signed char, character);
CLASSIFY(unsigned char, character);
CLASSIFY(char16_t, character);
CLASSIFY(char32_t, character);
CLASSIFY(wchar_t, wide_char);
CLASSIFY(bool, boolean);
CLASSIFY(float, floating);
CLASSIFY(double, floating);
CLASSIFY(long double, floating);
#undef CLASSIFY
template <typename T>
struct rank_numeric;
#define RANK(T, V) \
template <> \
struct rank_numeric<T> \
static constexpr int value = V; \
#define URANK(T, V) \
RANK(T, V); \
RANK(unsigned T, V)
RANK(bool, 0);
RANK(signed char, -1);
URANK(char, 0);
RANK(char16_t, 1);
RANK(char32_t, 2);
URANK(short, 1);
URANK(int, 2);
URANK(long, 3);
URANK(long long, 4);
RANK(float, 0);
RANK(double, 1);
RANK(long double, 2);
#undef RANK
【讨论】:
以上是关于C++:在编译时确定给定整数类型的整数转换等级?的主要内容,如果未能解决你的问题,请参考以下文章