N维向量的递归变异模板函数

时间:2017-07-20 21:05:56

标签: c++ templates recursion vector variadic

我现在一直在努力想出这个问题,而我似乎无法做到这一点。

我想要做的是创建一个模板函数,它需要任意数量的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维字符串向量,其中插入的数据由这些字符分隔。例如,假设我传入的std :: string看起来像这样:

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

然后我希望这个函数返回一个n维向量(模板类型字符串),可以像这样访问:

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

虽然如果提前知道向量的大小(仅使用大量的for循环),这并不困难,但当数据包含任意数量的分隔符时(这意味着很难)矢量可以是任何维度)。 这可能与递归可变参数模板有关吗?如果是这样,我真的不知道从哪里开始。

2 个答案:

答案 0 :(得分:1)

如果分隔符从上到下列出,更高级别,则更容易。如果那样可以,那就是这些:

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

答案 1 :(得分:0)

我会使用更容易专业化的结构:

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)
}

注意:

  • 我让split方法作为练习。
  • 分隔符顺序相反。