如何将用户定义的文字中的可变字符模板参数转换回数字类型?

发布于 2024-12-15 08:05:40 字数 1306 浏览 1 评论 0原文

由于这个而提出这个问题

C++11 允许您为数字文字定义如下文字:

template<char...> OutputType operator "" _suffix();

这意味着 503_suffix 将变为 <'5','0','3'>

这很好,尽管它的形式不是很有用。

如何将其转换回数字类型?这将变成<'5','0','3'> 转换为 constexpr 503。此外,它还必须适用于浮点文字。 <'5','.','3> 会变成 int 5float 5.3

在 < a href="https://stackoverflow.com/questions/8108473/user-define-literal-arguments-are-not-constexpr/8108872">上一个问题,但它没有处理非整数:

template <typename t>
constexpr t pow(t base, int exp) {
  return (exp > 0) ? base * pow(base, exp-1) : 1;
};

template <char...> struct literal;
template <> struct literal<> {
  static const unsigned int to_int = 0;
};
template <char c, char ...cv> struct literal<c, cv...> {
  static const unsigned int to_int = (c - '0') * pow(10, sizeof...(cv)) + literal<cv...>::to_int;
};
// use: literal<...>::to_int
// literal<'1','.','5'>::to_int doesn't work
// literal<'1','.','5'>::to_float not implemented

This question is being asked because of this one.

C++11 allows you to define literals like this for numeric literals:

template<char...> OutputType operator "" _suffix();

Which means that 503_suffix would become <'5','0','3'>

This is nice, although it isn't very useful in the form it's in.

How can I transform this back into a numeric type? This would turn <'5','0','3'> into a constexpr 503. Additionally, it must also work on floating point literals. <'5','.','3> would turn into int 5 or float 5.3

A partial solution was found in the previous question, but it doesn't work on non-integers:

template <typename t>
constexpr t pow(t base, int exp) {
  return (exp > 0) ? base * pow(base, exp-1) : 1;
};

template <char...> struct literal;
template <> struct literal<> {
  static const unsigned int to_int = 0;
};
template <char c, char ...cv> struct literal<c, cv...> {
  static const unsigned int to_int = (c - '0') * pow(10, sizeof...(cv)) + literal<cv...>::to_int;
};
// use: literal<...>::to_int
// literal<'1','.','5'>::to_int doesn't work
// literal<'1','.','5'>::to_float not implemented

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

零崎曲识 2024-12-22 08:05:40

总有简单的方法。非类型参数包可以扩展为初始化列表,如下所示:

#include <iostream>

template<char... Chars>
  double
  operator "" _suffix()
  {
    const char str[]{Chars..., '\0'};
    return atof(str);
  }

int
main()
{
  std::cout << 123.456789_suffix << std::endl;
}

There's alwars the easy way. A non-type parameter pack can be expanded into an initializer list as follows:

#include <iostream>

template<char... Chars>
  double
  operator "" _suffix()
  {
    const char str[]{Chars..., '\0'};
    return atof(str);
  }

int
main()
{
  std::cout << 123.456789_suffix << std::endl;
}
潦草背影 2024-12-22 08:05:40

我认为以下内容应该适用于没有指数部分的浮点数(未经测试):

template<bool fp, long long num, long long denom, char ...> struct literal;

template<bool fp, long long num, long long denom> struct literal<fp, num, denom>
{
   static constexpr double value() { return (1.0*num)/denom; }
};

template<long long num, long long denom, char digit, char... rest>
  struct literal<false, num, denom, digit, rest...>
{
  static constexpr double value()
  {
    return literal<false, 10*num + (digit-'0'), denom, rest...>::value();
  }
};

template<long long num, long long denom, char digit, char... rest>
  struct literal<true, num, denom, digit, rest...>
{
  static constexpr double value()
  {
    return literal<true, 10*num + (digit-'0'), 10*denom, rest...>::value();
  }
};

template<long long num, long long denom, char... rest>
  struct literal<false, num, denom, '.', rest...>
{
  static constexpr double value()
  {
    return literal<true, num, denom, rest...>::value();
  }
};

template<char... c> double operator "" _dbl()
{
  return literal<false, 0, 1, c...>::value();
}

如何将其扩展为也采用指数部分应该是显而易见的。

当然,人们还想做一些错误检查(确保字符确实是数字)。

I think the following should work on floats without exponential part (untested):

template<bool fp, long long num, long long denom, char ...> struct literal;

template<bool fp, long long num, long long denom> struct literal<fp, num, denom>
{
   static constexpr double value() { return (1.0*num)/denom; }
};

template<long long num, long long denom, char digit, char... rest>
  struct literal<false, num, denom, digit, rest...>
{
  static constexpr double value()
  {
    return literal<false, 10*num + (digit-'0'), denom, rest...>::value();
  }
};

template<long long num, long long denom, char digit, char... rest>
  struct literal<true, num, denom, digit, rest...>
{
  static constexpr double value()
  {
    return literal<true, 10*num + (digit-'0'), 10*denom, rest...>::value();
  }
};

template<long long num, long long denom, char... rest>
  struct literal<false, num, denom, '.', rest...>
{
  static constexpr double value()
  {
    return literal<true, num, denom, rest...>::value();
  }
};

template<char... c> double operator "" _dbl()
{
  return literal<false, 0, 1, c...>::value();
}

How to extend this to also take an exponential part should be obvious.

Of course one would also want to do some error checking (make sure that the characters are indeed digits).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文