24

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

让它调用一个constexpr函数是可行的,但是它不允许我用模板来做,因为编译器抱怨参数 is not 和 cannot be constexpr

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

第一种方法:

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

5 回答 5

12

我不知道 C++11 中是否有比当前接受的答案更好的方法来做到这一点,但是constexpr在 C++14 中放松,您可以编写“正常”代码:

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, "!");
于 2017-01-28T20:48:25.810 回答
5

这就是我最终这样做的方式:

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!

于 2011-11-13T00:49:23.283 回答
4

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

于 2011-11-13T01:22:59.903 回答
3

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

于 2011-11-12T23:58:11.230 回答
1

@小熊。消化 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 样式函数添加一个空字符。

于 2011-11-13T05:48:37.647 回答