用户定义的文字参数不是 constexpr?

发布于 2024-12-15 07:57:24 字数 885 浏览 3 评论 0原文

我正在测试用户定义的文字。我想让 _fac 返回数字的阶乘。

让它调用 constexpr 函数是可行的,但是它不允许我使用模板来执行此操作,因为编译器会抱怨参数不是也不可能是 constexpr。

我对此感到困惑 - 文字不是常量表达式吗? 5_fac 中的 5 始终是可以在编译时计算的文字,那么为什么我不能这样使用它呢?

第一种方法:

constexpr int factorial_function(int x) {
  return (x > 0) ? x * factorial_function(x - 1) : 1;
}

constexpr int operator "" _fac(unsigned long long x) {
  return factorial_function(x); // this works
}

第二种方法:

template <int N> struct factorial_template {
  static const unsigned int value = N * factorial_template<N - 1>::value;
};
template <> struct factorial_template<0> {
  static const unsigned int value = 1;
};

constexpr int operator "" _fac(unsigned long long x) {
  return factorial_template<x>::value; // doesn't work - x is not a constexpr
}

I'm testing out user defined literals. I want to make _fac return the factorial of the number.

Having it call a constexpr function works, however it doesn't let me do it with templates as the compiler complains that the arguments are not and cannot be constexpr.

I'm confused by this - aren't literals constant expressions? The 5 in 5_fac is always a literal that can be evaluated during compile time, so why can't I use it as such?

First method:

constexpr int factorial_function(int x) {
  return (x > 0) ? x * factorial_function(x - 1) : 1;
}

constexpr int operator "" _fac(unsigned long long x) {
  return factorial_function(x); // this works
}

Second method:

template <int N> struct factorial_template {
  static const unsigned int value = N * factorial_template<N - 1>::value;
};
template <> struct factorial_template<0> {
  static const unsigned int value = 1;
};

constexpr int operator "" _fac(unsigned long long x) {
  return factorial_template<x>::value; // doesn't work - x is not a constexpr
}

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

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

发布评论

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

评论(5

脸赞 2024-12-22 07:57:24

我不知道 C++11 中是否有比当前接受的答案更好的方法,但是使用 C++14 中的宽松 constexpr ,您可以编写“正常”代码:

constexpr unsigned long long int operator "" _fac(unsigned long long int x) {
    unsigned long long int result = 1;
    for (; x >= 2; --x) {
        result *= x;
    }
    return result;
}

static_assert(5_fac == 120, "!");

I don't know if there's a better way in C++11 to do this than the current accepted answer, but with relaxed constexpr in C++14, you can just write "normal" code:

constexpr unsigned long long int operator "" _fac(unsigned long long int x) {
    unsigned long long int result = 1;
    for (; x >= 2; --x) {
        result *= x;
    }
    return result;
}

static_assert(5_fac == 120, "!");
不顾 2024-12-22 07:57:24

这就是我最终的做法:

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;
};

template <int N> struct factorial {
  static const unsigned int value = N * factorial<N - 1>::value;
};
template <> struct factorial<0> {
  static const unsigned int value = 1;
};

template <char ...cv>
constexpr unsigned int operator "" _fac()
{
  return factorial<literal<cv...>::to_int>::value;
}

非常感谢 KerrekSB!

This is how I ended up doing it:

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;
};

template <int N> struct factorial {
  static const unsigned int value = N * factorial<N - 1>::value;
};
template <> struct factorial<0> {
  static const unsigned int value = 1;
};

template <char ...cv>
constexpr unsigned int operator "" _fac()
{
  return factorial<literal<cv...>::to_int>::value;
}

Huge thanks to KerrekSB!

濫情▎り 2024-12-22 07:57:24

我可能是错的,但我认为 constexpr 函数也可以使用非常量参数调用(在这种情况下,它们不给出常量表达式并在运行时评估)。这不适用于非类型模板参数。

I may be wrong, but I think constexpr functions can also be called with non-constant arguments (in which case they don't give a constant expression and are evaluated at runtime). Which wouldn't work well with non-type template arguments.

紫瑟鸿黎 2024-12-22 07:57:24

为了将 constexpr 与用户定义的文字一起使用,您显然必须使用可变参数模板。请查看维基百科文章中的第二个列表例子。

In order to make use of constexpr with user defined literals, you apparently have to use a variadic template. Take a look at the second listing in the wikipedia article for an example.

梨涡 2024-12-22 07:57:24

@Pubby。消化 char 非类型参数包的简单方法是将其捕获到字符串的初始值设定项列表中。然后您可以使用 atoi、atof 等:

#include <iostream>

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

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

记住为 C 风格函数添加一个空字符。

@Pubby. The easy way to digest the char non-type parameter pack is to cature it into an initializer list for a string. Then you can use atoi, atof, etc:

#include <iostream>

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

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

Remember to tack on a null character for the C-style functions.

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