【问题标题】:Recursive Variadic Template Function For N-Dimensional VectorN维向量的递归可变参数模板函数
【发布时间】:2017-07-20 21:05:56
【问题描述】:

我一直在努力解决这个问题,但我似乎无法做到。

我想做的是创建一个模板函数,它需要任意数量的 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 循环),这并不难做到,但当数据包含任意数量的定界符时(意味着向量可以是任何维度)。 这可能与递归可变参数模板有关吗?如果是这样,我真的不知道从哪里开始。

【问题讨论】:

    标签: c++ templates recursion vector variadic


    【解决方案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

    【讨论】:

    • 哇,太棒了。我需要一段时间才能完全理解这里发生了什么,但我真的印象深刻。干得好!
    【解决方案2】:

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

    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方法作为练习。
    • 定界符的顺序颠倒了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-02-23
      • 1970-01-01
      • 1970-01-01
      • 2012-05-17
      • 2013-08-04
      • 2016-12-11
      • 1970-01-01
      相关资源
      最近更新 更多