ユーザー定義のリテラル引数はconstexprではありませんか?

私はユーザー定義のリテラルをテストしています。 _fac に数値の階乗を戻したいと思います。

constexpr 関数を呼び出すと、コンパイラは引数がなく、 constexpr できないと文句を言います。

私はこれで混乱しています - リテラル定数式ではありませんか? 5_fac5 は常にコンパイル時に評価できるリテラルなので、どうしてこのように使うことはできませんか?

最初の方法:

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
}

第2の方法:

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

constexpr int operator "" _fac(unsigned long long x) {
  return factorial_template::value;//doesn't work - x is not a constexpr
}
23
私はまだコンパイラがこれらのユーザ定義のリテラルを実装しているとは思わない。どのようにこれをテストしていますか?
追加された 著者 Kerrek SB,
ニース!私はそれがまだサポートされていたのか分からなかった。私はそれらのうちの1つをどこかのマシンにインストールしていますが、今はそれらのバリデーションテンプレートを試してみたいと思います:-)
追加された 著者 Kerrek SB,
@KerrekSB GCC 4.7スナップショット
追加された 著者 Pubby,

5 答え

私は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, "!");
9
追加された

私は間違っているかもしれませんが、constexpr関数は非定数引数で呼び出すこともできると思います(その場合、定数式を与えず、実行時に評価されます)。非型テンプレート引数ではうまくいかないでしょう。

4
追加された
@MichaelPrice:もちろん、非const式をconstexpr関数に渡すことについて不平を言うことができます(私が言ったように、私は正しいとは確信していません)。しかし、これは通常、 constexpr キーワードを除いて全く同じ2つの関数が必要であることを意味します.1つは定数式用、もう1つは他の式用です。
追加された 著者 celtschk,
おそらく、関数に非コンパイル時定数を渡したとすれば、おそらく、コンパイラは文句を言うでしょう。これは、テンプレートのネスがコードのレイヤー全体を少しずつ盛り上げるという問題を解決する手段になりますか?
追加された 著者 Michael Price,

これが私のやり方です。

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

template  struct literal;
template <> struct literal<> {
  static const unsigned int to_int = 0;
};
template  struct literal {
  static const unsigned int to_int = (c - '0') * pow(10, sizeof...(cv)) + literal::to_int;
};

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

template 
constexpr unsigned int operator "" _fac()
{
  return factorial::to_int>::value;
}

KerrekSBへの感謝の気持ち!

4
追加された
回答は実際にOPに記載された質問に答えるのではなく、コードだけを含んでいるので、下降する。
追加された 著者 jotik,

ユーザー定義リテラルでconstexprを使用するには、variadicテンプレートを使用する必要があります。 ウィキペディアの記事の2番目のリストをご覧ください。例。

3
追加された
constexpr を使用するために必ずしもバリデーショナルテンプレートを使用する必要はありませんが、このケースでは必要です(ただし、あなたが意味するものは分かります)。
追加された 著者 Seth Carnegie,
char のバリデーションテンプレートを int にするにはどうすればよいですか?
追加された 著者 Pubby,
@SethCarnegie:修正済み
追加された 著者 Nate,
@Pubby - それから0x30を引く?私はより良い方法はわかりませんが、部分的なテンプレートの特殊化を使用することができますが、その考えは私の頭を傷つけます。
追加された 著者 Nate,
Wikipediaを参照する代わりに、例を挙げてみてはいかがですか?
追加された 著者 mceo,

@Pubby。 char型以外のパラメータパックを簡単にダイジェストするには、文字列の初期化子リストにそれを挿入します。次に、atoi、atofなどを使用できます。

#include 

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

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

Cスタイルの関数にはヌル文字を付けることを忘れないでください。

1
追加された
問題は constexpr ではないことです。実際には、 unsigned long long を引数の型として渡すよりも悪いです。
追加された 著者 Pubby,