C ++:在编译时确定给定整数类型的整数转换等级?

时间:2016-06-08 20:52:16

标签: c++ c++11

在我正在开发的项目中,我有一个数据结构,可以存储各种类型的数据,并且需要保证不会意外丢失精度/信息。

因为标准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转换为conversion rank是合法的。这将使我的程序不可移植 - 开发人员可以编写在其机器上编译和工作的代码,并且事实上,不会失去精度。但在其他一些机器上,它可能无法编译并抱怨不安全的转换,可能。

我真正想要的是获得[4.13] [conv.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

如果我想为整数类型做这个...还有更多它们。

还有一个问题是不需要存在整数类型,所以我可能想尝试检测那个场景,以便编译boost模板。

有没有更好/标准的方法来解决这个问题?我没有在标准库中找到“conversion_rank”元函数,我想标准实际上并没有给出数值,它只是指定“更高”和“更低”。但也许sizeof /某些其他策略中的某些内容不那么费力且不依赖于for i in {130..136}; do > ./vserver/Info$i ssh 132.138.180.$i "hostname; echo 'Virtual' echo '' cat /etc/issue | head -1 echo '' dmidecode | grep Socket | tail -1 | awk '{print \$4}' echo '' free -g | grep Mem | awk '{ print \$2 }' echo '' fdisk -l | grep Disk | wc -l echo '' df -h | grep ^/ | wc -l echo '' ifconfig | grep inet | awk '{print \$2 }' | cut -c 6- | awk '\$1=\$1' ORS=' ' echo '' ifconfig | grep -b1 inet | grep HWaddr | awk '{ print \$5 }' | awk '\$1=\$1' ORS=' ' echo '' ip route show | grep default | awk '{ print \$3 }' | awk '\$1=\$1' ORS=' ' echo '' cat /etc/resolv.conf | grep name | awk '{ print \$2 }' | awk '\$1=\$1' ORS=' ' echo '' mount | grep el01 | awk '{ print \$1 \" -> \" \$3 }' | awk '\$1=\$1' ORS=' ' echo '' netstat -nr | awk '{ print \$1, \$2, \$3, \$8 }' echo '' " >> ./vserver/Info$i done

1 个答案:

答案 0 :(得分:0)

我开源的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