2017-07-20 8 views
1

私はこれをしばらく前から把握するのに苦労していました。N次元ベクターのための再帰的バリアリテンプレート関数

私がしたいのは、任意の数のcharパラメータ引数を必要とするテンプレート関数を作成し、次にパラメータとして単一のstd :: stringを作成することです。構文の例は次のようになります。

nvec<3, std::string> info = string_to_vec<':', ';', '-'>(data); 

nvecは、特定の型にテンプレート化されたn次元ベクトルを作成する再帰的テンプレートクラスです。そのコードはかなり単純であり、ここで見ることができます:

template <size_t dim, typename T> 
struct multidimensional_vector 
{ 
    typedef std::vector<typename multidimensional_vector<dim - 1, T>::type> type; 
}; 

template <typename T> 
struct multidimensional_vector<0, T> 
{ 
    typedef T type; 
}; 

template <size_t dim, typename T> 
using nvec = typename multidimensional_vector<dim, typename T>::type; 

しかし、string_to_vecは、任意の文字パラメータの数(ただし、少なくとも一つ)を必要とする可能性があります。次に、この情報を使って行う必要があるのは、対応するn次元文字列ベクトルを返します。これらの文字列ベクトルは、それらの文字で区切られて挿入されます。それから私は、n次元のベクトルを返すために、この機能を期待する

std::string data = "1:2:3;4:5:6;7:8:9-10:11:12;13:14:15;16:17:18" 

(文字列型でテンプレート化)このようにアクセス可能性がある:例えば、私が合格のstd ::文字列はこのようになっていることを言うことができます:これは行うことは難しいことではありません

info[0][0][0] // = 1 
info[1][0][0] // = 10 
info[1][1][1] // = 14 
info[1][2][2] // = 18 
// etc. 

がベクトルの大きさは(ちょうどループのための多くを使用します)事前にわかっている場合、データが区切り文字の任意の数が含まれている場合、それは非常に困難になります(ベクトルは任意の次元になり得ることを意味する)。 これは再帰的なバリデーションテンプレートで可能ですか?もしそうなら、私は正直にどこから始めたらいいのかわかりません。

答えて

0

デリミタが上から下に、より高いレベルで最初にリストされている方が簡単です。それはOKだ場合、これらの線に沿って何か:

template <char... Cs> struct string_to_vec_impl; 

template <> struct string_to_vec_impl<> 
{ 
    const std::string& operator()(const std::string& s) const { return s; } 
}; 

template <char C, char...Cs> struct string_to_vec_impl<C, Cs...> 
{ 
    nvec<1 + sizeof...(Cs), std::string> operator()(const std::string& s) const 
    { 
     std::vector<std::string> words = split(s, C); // split string by character c 
     nvec<1 + sizeof...(Cs), std::string> res; 
     for (const auto& word : words) { 
      res.push_back(string_to_vec_impl<Cs...>{}(word)); 
     } 
     return res; 
    } 
}; 

template <char...Cs> 
auto string_to_vec_impl(const std::string& s) 
{ 
    return string_to_vec_impl<Cs...>(s) 
} 

注:

template <char... delims> 
struct StringToVecHelper { 
    static std::string convert(const std::string& data) { return data; } 
}; 

template <char delim, char... tail> 
struct StringToVecHelper<delim, tail...> { 

static nvec<sizeof...(tail)+1, std::string> convert(const std::string& data) { 
    nvec<sizeof...(tail)+1, std::string> result; 
    size_t start = 0; 
    for (;;) { 
     size_t pos = data.find(delim, start); 
     std::string piece(data, start, pos - start); 
     result.push_back(StringToVecHelper<tail...>::convert(piece)); 
     if (pos == std::string::npos) break; 
     start = pos + 1; 
    } 
    return result; 
} 
}; 

template <char... delims> 
auto string_to_vec(const std::string& data) { 
    return StringToVecHelper<delims...>::convert(data); 
} 

Demo

+0

うわー、絶対に素晴らしい。ここで何が起こっているのかを完全に理解するには、しばらく時間がかかりますが、私は本当に感心しています。すごい仕事! – JohnTravolski

0

私が専門とする方が簡単である構造使用することになり

  • を私はsplitてみましょう方法を練習として。
  • 区切り文字の順序が逆になります。
関連する問題