2016-11-12 4 views
1

std::fscanf()という幾分兄弟を作りたいと思っています(私はそれがCの関数だと知っています)。私はそれだけで一つの配列(引数の一部)ではなく、引数とフォーマットを維持するために、プログラマを必要とするので、コンソールからの読み取りのC#バージョンを実装することを決定した(疑似)実行時に可変長テンプレートパックを反復処理する方法は?

template <charT, char_traits, ...> 
std::size_t ts_scanf(is, format, opening_bracket, closing_bracket, args) 

:だから、私のインターフェイスは、このようなものです。ここ

方法C#バージョン作品です

"text blah blah blah {0} {1} {0}", arg1, arg2 

だから、ARG1の種類、ARG2を推論し、次に{N}は、適切な引数に待機位置にテキストを読み取ります。

私が何をしたいのアルゴリズム:int型を解析する

1.Findオープニングブラケット

2.Try、N

3.Ifはが成功したと言う、N番目のパラメータを取得しますパックから、is>>get<N>argsを使用してそれを読んでください。失敗した4.if

、ダムは、フォーマットの最後まで4に

5.Repeat 1を読んだり、流れがそう

を使い果たすまでループを書くとき、私は問題が発生し実行します。

for (i = 0; i < length; i = format.find(i, opening_bracket)) 

パラメータパックargsを何とか展開する必要があることがわかりました。これは実行時には不可能です(ループは実行時です)。私が念頭に置いている唯一の解決策は、反復的な解決策です:オープニングブラケットを見つけるときにそれを読んで、フォーマット文字列をトリミングし、トリミングされた文字列と残りのバリッドパックで再帰します。

質問:は、(擬似)実行時に可変長パックを展開することが可能な解決策がありますか?

+0

「opening_bracket」と「closing_bracket」とは何ですか?なぜそれが必要ですか? 'fscanf'にはAFAIKのようなものはありません。あなたがそれを働かせたいと思う方法に関する擬似コードは、それを言葉で表現するよりも説明するのに長い道のりがあります。 – Arunmu

+0

@Arunmu、ありがとうございました。 – Incomputable

+0

あなたが本当に効率的にやりたければ、式テンプレートを使ってコンパイル時にそれを達成する必要があります(マッピング)。これは 'boost :: proto'を使って行うことができますが、私はそれが弱い心のためではないことを認めます:)。私が知っている他の解決策は、実行時にのみブラケットを解析するため、純粋にランタイムです。これには、実行時コンテナにargsを格納することが含まれます。 – Arunmu

答えて

2
template<class=void, std::size_t...Is > 
auto indexer(std::index_sequence<Is...>){ 
    return [](auto&&f)->decltype(auto){ 
    return decltype(f)(f)(std::integral_constant<std::size_t, Is>{}...); 
    }; 
} 
template<std::size_t N> 
auto indexer(){ 
    return indexer(std::make_index_sequence<N>{}); 
} 
template<std::size_t N> 
void for_each(F&& f) { 
    indexer<N>()([&](auto...Is){ 
    using discard=int[]; 
    (void)discard{0,(void(
     f(Is) 
    ),0)...}; 
    }); 
} 

indexerは、アンパックされたインデックスを表示します。

for_eachNまでの各iのコンパイル時間i値でfを呼び出します。

これは、コンパイル時に整数を反復できるようにします。時間をコンパイルし、実行時に整数をマップするには:

template<std::size_t N, class F> 
void pick(std::size_t I, F&& f){ 
    for_each<N>([&](auto i){ 
    if (I==i) f(i); 
    }); 
} 

をこれは、それがN未満であるようIのコンパイル時のバージョンでfを起動します。

ここで、上記で暗黙的に記述されたifがあります。別の手法を使用してジャンプテーブルに置き換えることができます。

コードはコンパイルされません。デザインは健全ですが、おそらくタップがあります。インデクサーはgoogleで見つけることができます(私はそれ以前にそれを書いています)。私はfor_eachとして直接書きましたが、私は単一パックのバージョンがあまりにも有用であると感じています。ここで私は別のパックのバージョンが必要でした。ピックだけでそれを使用します。含まれていないのチェック

template<std::size_t N, class F> 
void pick(std::size_t I, F&& f){ 
    indexer<N>()([&](auto...Is){ 
    using table_f=void(*)(&f); 
    const table_f table[]={ 
     +[](F&f){ f(decltype(Is){}); }... 
    }; 
    table[I](f); 
    }); 
} 

バウンド:ここ

は、ピックのジャンプテーブルのバージョンです。このバージョンはfor_eachを必要としませんが、いくつかのコンパイラは、ステートメントの中で展開されていないパラメータパックを持つラムダを持つかどうかを尋ねると中断します。

+1

Thanks Template-Yoda。 –

関連する問題