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可以提升为doublelong doubledouble可以提升为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&lt;Source&gt;() 的良构性? 这正是我希望得到的答案,谢谢! 其实我收回了。如果你想要完全的可移植性,你必须用等级来写这个。 将允许 long longlong 在 LP64 上。 @T.C. long longlong 的转换是标准允许的,还是编译器中的错误? 我很确定给定两个整数类型T1T2 具有相同的大小但转换排名低于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++:在编译时确定给定整数类型的整数转换等级?的主要内容,如果未能解决你的问题,请参考以下文章

替代 itoa() 将整数转换为字符串 C++? [复制]

C 无符号整数减法、宏和类型转换

转换为指向运行时确定大小的数组的指针

C++转换构造函数:将其它类型转换为当前类的类型

C++ 无法从枚举转换为 LPCTSTR [关闭]

如何在 C++ 中将一组整数转换为 3D 向量?