【问题标题】:C++: Determine the integral conversion rank of a given integral type at compile time?C++:在编译时确定给定整数类型的整数转换等级?
【发布时间】: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 对 Dest{std::declval&lt;Source&gt;()} 的良构性?
  • 这正是我希望得到的答案,谢谢!
  • 其实我收回了。如果你想要完全的可移植性,你必须用等级来写这个。 {} 将允许 long longlong 在 LP64 上。
  • @T.C. long longlong 的转换是标准允许的,还是编译器中的错误?
  • 我很确定给定两个整数类型T1T2 具有相同的大小但转换排名低于int,无法确定哪个具有更大的排名使用通常的 TMP 技术,无需对其进行硬编码。因此,如果您想要 100% 的可移植性,您要么必须自己进行硬编码,要么找人为您完成 :)

标签: c++ c++11


【解决方案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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-06
    • 1970-01-01
    • 2011-10-15
    相关资源
    最近更新 更多