2016-11-21 8 views
1

"foobar.png"などの画像名を表す文字列があります。 C++のswitch-caseは文字列の切り替えをサポートしていません。文字列を定数に変換するには?

私はこれを回避するために、文字列をstd :: size_tにハッシュし、その値をswitch-caseステートメントで使用しています。

 //frameName is an std::string which represents foobar.png etc.. 
     switch (shs(frameName)) { //shs is my hash func which returns std::size_t; 
      case shs(Pfn::fs1x1): //Problem in this line 
      default:{ 
       break; 
      } 
     } 

別個のファイル(Pfn.hpp)において:例えば

名前空間PFN { のconstのstd ::文字列fs1x1 = "fs1x1"。 };

問題は、私の場合、ステートメントでは、shs(Pfn::fs1x1)が定数式ではないことをコンパイラーが報告しているということです。正確なエラーメッセージは次のとおりです。事前にすべてのハッシュ値をうまくして、case文にそれらをハードコーディングすることは本当に退屈だろう

ケース値は定数式ではありません。実行時に何とか定数式を作成する方法について提案がありますか?

EDIT:私のSHS機能:定義により

static std::size_t shs(std::string string){ 
    return Hash::shs::hs(string); 
} 

// ...

namespace Hash{ 
    struct shs{ 
    public: 
     inline std::size_t operator()(const std::string &string)const{ 
      return hashString(string); 
     } 

     static std::size_t hs(const std::string &string){ 
      std::size_t seed = 0; 
      hash_combine(seed,string); 
      return seed; 
     } 

     //From Boost::hash_combine. 
     template <class T> 
     static inline void hash_combine(std::size_t& seed, const T& v) 
     { 
      std::hash<T> hasher; 
      seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); 
     }; 
    }; 
} 
+0

あなたの関数 'shs'を追加できますか? –

答えて

3

shsの引数はconstexprshs自体も同様constexprである必要がありますする必要があります。おそらく、constexpr関数のC++ 11の制約のために、コンパイル時のバージョンと実行時のバージョンの異なる実装を提供する可能性があります。

私はwroteこの非常にトピックの投稿はしばらく前に、fnv1aをハッシュアルゴリズムとして使用しています。

定数::ここで重要な部分はある

typedef std::uint64_t hash_t; 

constexpr hash_t prime = 0x100000001B3ull; 
constexpr hash_t basis = 0xCBF29CE484222325ull; 

ランタイムハッシュ:

hash_t hash(char const* str) 
{ 
    hash_t ret{basis}; 

    while(*str){ 
     ret ^= *str; 
     ret *= prime; 
     str++; 
    } 

    return ret; 
} 

コンパイル時のハッシュ:リテラル

constexpr hash_t hash_compile_time(char const* str, hash_t last_value = basis) 
{ 
    return *str ? hash_compile_time(str+1, (*str^last_value) * prime) : last_value; 
} 

ユーザー定義の文字列:

constexpr unsigned long long operator "" _hash(char const* p, size_t) 
{ 
    return hash_compile_time(p); 
} 

と使用方法:

switch(fnv1a_64::hash(str)){ 
case "first"_hash: 
    cout << "1st one" << endl; 
    break; 
case "second"_hash: 
    cout << "2nd one" << endl; 
    break; 
case "third"_hash: 
    cout << "3rd one" << endl; 
    break; 
default: 
    cout << "Default..." << endl; 
} 

demo

しかししてください、子供を考えます! がハッシュコリジョンを起こさないことが保証されている場合を除き、これは火災で再生されており、プロダクションコードには適していません。

+0

Hmm ..正直言って、私のアプリのイメージアセットは準備ができておらず、自分の "フロー"を中断して、自分でイメージを作成してアプリで使用する必要があるので、ちょうどハッキングして、プロダクションイメージが準備できるまでスイッチケースを使って飛んでください。あなたのハッシュ関数の仕組みを説明できますか?オペレータの過負荷 ""その興味をそそられる...私はあなたがそれを行うことができるかどうかを知りませんでした... –

+0

私が使用している有限の文字列があるならば、私はすべての文字列に対してこの関数を呼び出し、衝突をチェックできます決定的で、すべてのプラットフォームで同じ値を返さなければなりません... "プライム"はどこに定義されていますか?私はプライムを使うことができますか? –

+0

@ジョンよく、ハッシュが進む限り、私は単にfnv1a(リンク)を実装しました。ユーザー定義のリテラルは、C++ 11の新しい追加機能です。あなたが見ることができるように、それは 'constexpr'自身であり、コンパイル時にハッシュを生成できる関数にconstexprデータを渡します。私はこれについて他に何を言うべきか分からないが、離れて尋ねる。私は100%確実ではないが、いくつかの素数はおそらく他の素数よりも優れているだろう、私はアルゴリズム作成者によって提案されたものを使用した。 – krzaq

1

、定数式はコンパイル時に評価できる式を意味します。

func()constexprの場合は、case func():を使用できます。

+0

私の問題を回避する方法はありますか? –

2

私は、あなたのハッシュがこの回答のために衝突を起こさないと仮定します。

代わりに、ハッシュをプリプロセッサ関数として定義すると、一致する定数を作成できます。

この投稿は役立つかもしれない:Compile-time (preprocessor) hashing of string