0

次のコードは、最大 8 文字の長さの文字列の単純なハッシュのようなものを作成するためのものです。

#include <type_traits>
#include <cstdint>
#include <iostream>

template<std::size_t N, std::size_t n=N>
constexpr typename std::enable_if<N<=9 && n==0,
uint64_t>::type string_hash(const char (&)[N])
{
    return 0;
}

template<std::size_t N, std::size_t n=N>
constexpr typename std::enable_if<N<=9 && n!=0,
uint64_t>::type string_hash(const char (&array)[N])
{
    return string_hash<N,n-1>(array) | ((array[n-1]&0xffull)<<(8*(n-1)));
}

通常の文字列リテラルと constexpr NULL で終わる文字列の場合、実際には正常に機能します。しかし、私がこのようなことをすると:

constexpr char s2[] = {1,2,3,4,5,6,7,8,9};
std::cout << string_hash(s2) << "\n";

、出力は string の場合と同じになります"\x1\x2\x3\x4\x5\x6\x7\x8"static_assert(array[N-1]==0,"Failed");の定義にa を追加しようとしましたstring_hashが、コンパイラはそれarray[N-1]は定数式ではないと言います。次に、パラメーターを宣言しようとしましたconstexprが、コンパイラーはパラメーターを宣言できないと言いましたconstexpr

次に、このチェックを行うにはどうすればよいですか?

4

2 に答える 2

2

constexpr関数はコンパイル時に使用できますが、必須ではないことに注意してください。コンパイル時にパラメータが不明な場合、静的アサーションを評価できないため、実行時パラメータに静的アサーションを追加することはできません。

できることは、非関数に対してできることと同じですconstexpr: 何かを投げます。これにより、関数が無効な入力で呼び出されるのを防ぐことはできませんが、暗黙の間違った結果を防ぐことができます。また、関数が定数式を必要とするコンテキストで使用されている場合、コンパイラはそれが定数値を返さないものとして正しく検出します。

関数の本体は、constexprC++11 では単一の return ステートメントである必要がありますが、それでもそこに収めることができます。

return array[N-1] ? throw "bad!" : <your current return expression here>;

ただし、投げるのに適したものを選んでください。

于 2015-08-01T14:53:28.897 に答える
0

コンパイラが不平を言っている理由は、関数がインスタンス化さarrayれている時点で不明であるためです。呼び出し時ではなく、インスタンス化時に評価されます (constexpr 関数であっても)。string_hash<N,n>static_cast

<N,n>値のペアごとに 1 つの関数が作成されることに注意してください。同じ長さの constexpr 文字列を 2 つ使用すると、まったく同じインスタンスstring_hashが使用されますが、引数によってarray[N-1]は異なる結果になる場合があります。

必要に応じて、引き続きご質問に対する正確な回答を探します。ただし、「簡単な修正」として、ハッシュ関数を変更して、0 であろうとなかろうと常に最後の文字が計算に含まれるようにすることをお勧めしますか?

更新: いくつかの掘り下げを行った後、私constexpr_assertはあなたがおそらくあなたのケースで何を望んでいるのか、そしてそれが現在標準に欠けていることを知りました. うまくいけば、彼らは将来それを追加します。以下を確認してください。

于 2015-08-01T14:48:23.767 に答える