【问题标题】:Is there a way to "convert string to vector<int>"?有没有办法“将字符串转换为向量<int>”?
【发布时间】:2014-08-06 03:16:51
【问题描述】:

我对编程比较陌生,目前正在学习 C++。我怀疑我的逻辑是否正确,但这是我一直在努力解决的问题:

我有一个简单的程序,可以输出向量的大小和内容;

vector<int> v1;
vector<int> v2(10);
vector<int> v3(10, 42);
vector<int> v4{ 10 };
vector<int> v5{ 10, 42 };
vector<string> v6{ 10 };
vector<string> v7{ 10, "hi" };
//and so on...........

bool firstPass= true;
for (auto i : v3){
    if (firstPass) cout << "Vector size:  " << v3.size() << ".\nElements: " << i << ", ";
    cout << i << ", ";
    firstPass= false;
}

如果我想遍历另一个向量,我必须手动将 v3 更改为 vX,但我希望这段 sn-p 代码能够遍历所有向量。

我尝试了几种方法,例如创建一个 vector&lt;string&gt; V8{"v1","v2","v3"..}
for (auto i : V8[counter])

但基本上我失败了,因为“v1”!= v1。(这是我得到“将字符串转换为向量”的想法的地方,但有些事情告诉我这不是这样做的方法.. .)

任何帮助和批评都将不胜感激,我很抱歉,因为考虑到我试图解决这个问题的方法可能有问题,我提出了错误的问题,这可能会被提交得太具体甚至无用!

【问题讨论】:

  • 如果你想迭代向量,最简单的方法是将它们全部放在一个可迭代的容器中 - 例如另一个向量。所以,你有vector&lt;vector&lt;int&gt;&gt; = { { }, {10}, {10,42}, {10}, {10,42} };。然后,您可以使用嵌套的 for 循环进行迭代。但是你不能这么容易地混合字符串——你可以有一个单独的vector&lt;vector&lt;string&gt;&gt;,或者你可以使用变体创建一个抽象层(boost::anyboost::variant,一个面向向量的OO运行时多态层次结构)。 . 它可能超出了你准备写的范围。
  • 或者,如果您的向量已经存在,您可以创建一个指向现有向量的向量(或只是一个初始化列表)。 (但您仍然需要不同类型向量的单独集合。)
  • @TonyD,向量的向量听起来不错,但我特别受到与以前相同的问题的困扰;我如何将大量现有向量添加到vector&lt;vector&lt;int&gt;&gt;,而不必为每个向量添加vectorOfVectors.push_back(vectorName)?以下代码每次都会写入 v1,v2,v3 来代替 vectorName,但这些都是字符串,因此类型错误:vectorOfVectors.push_back("v"+to.string(counter)) counter++;
  • @Boop 这不是语言的工作方式。您必须以某种方式 解决目标中的项目,并且在 C++ 中最终在编译时以 id 开头;不是运行时。该 id 可以是向量的向量,数组,你有什么,但它必须是编译时知道的不知何故。如果它是您自己的类,您可以维护一个实时的对象静态列表并转储该列表,但标准库不提供此类工具。 也许 是一个模板包装器,但我不明白这有什么值得麻烦的。可变参数预处理可能有优点,但同样,你必须不想要它。
  • @Boop:你有多少这样的向量?

标签: c++ vector data-conversion


【解决方案1】:

要解决通过表示变量名称的字符串查找变量的字面问题:POSIX 提供的唯一按名称查找全局变量的工具是dlsym()。它仅适用于全局变量,您必须使用 extern "C" 声明您的函数以抑制 C++ 名称重整(全局变量名称不会被重整)。

#include <vector>
#include <assert.h>
#include <dlfcn.h>

std::vector<int> v1;

int main () {
    void *h = dlopen(0, RTLD_NOW);
    void *v = dlsym(h, "v1");
    assert(v == &v1);
}

要使上面的示例工作,您需要使用g++ -rdynamic prog.cpp -ldl 进行编译。

这种技术的局限性在于,您需要先验知道返回的指针的类型,并进行相应的转换。

如果你愿意将你的数组“传递”给一个函数来为你打印出每个数组,你可以实现一个可变参数模板函数来做到这一点。

template <typename Vector>
void print_all_vectors (Vector v) {
    /* enforce we are only interested in vectors */
    const std::vector<typename Vector::value_type> &vr = v;
    std::cout << "Vector size:  " << vr.size() << ".";
    if (!vr.empty()) std::cout << "\nElements";
    bool first = true;
    for (auto i : vr) {
        std::cout << (first ? ": " : ", ") << i;
        first = false;
    }
    std::cout << '\n';
}

template <typename Vector, typename... Vectors>
void print_all_vectors (Vector v, Vectors... vectors) {
    print_all_vectors(v);
    print_all_vectors(vectors...);
}

上面代码中的第一个模板打印出一个向量。第二个模板函数递归地解包可变参数列表并将每个参数列表传递给第一个模板函数。

函数使用很简单,如下图所示:

std::vector<int> v1{1, 3, 5, 7};
std::vector<std::string> v2{"doh", "ray", "me"};
print_all_vectors(v1, v2);

【讨论】:

    【解决方案2】:

    您需要 C++11,但绝对有可能:

    template<typename V>
    void PrintVector(V const& v) {
      for (auto elem : v) std::cout << elem << " ";
      std::cout << std::endl;
    }
    template <typename V, typename ... Vectors>
    void PrintAll(V const& v1, Vectors... vtail)
    {
       PrintVector(v);
       PrintAll(vtail...);
    }
    PrintAll(v1, v2, v3, v4, v5, v6, v7, v8, v9);
    

    【讨论】:

    • +1 不确定这是否是我们想要的(问题的 '"V1" != v1" 投诉让我想到了某种方式来处理标识符更像文本 - 需要连接),但是重读vector V8{"v1","v2","v3"..} 的问题表明 OP 对这种方法持开放态度,这非常优雅....
    • @TonyD:OP 已经承认他的“字符串”想法可能是错误的开始方法。最后,您需要某种 方法来告诉编译器哪些对象需要组合在一起。显然,您不能只“打印程序中的每个向量”。如果std::cout 在内部使用了一个呢?!
    • 您的所有个人观点都是正确的,但它们听起来像是程序员键入的列表或某种天真的(在当前的 C++ 中不存在)内省是唯一的选择。无论如何,我确信我们都知道提供什么以及替代方案是什么 - 数组 / 向量 / template &lt;int N&gt; ... / 预处理器迭代 / dlsym 使用一些命名约定 / 代码生成脚本等等等..
    • @TonyD:酸葡萄,因为这基本上是我一个小时前发布的答案。
    【解决方案3】:

    如果您需要在运行时解决的问题,则需要进行迭代,您可以使用向量的向量,但它们应该是相同的类型(字符串向量与 int 混合是不可能的,因为它们是不同的类型由于模板实例化) 另一方面,您可以将预处理器和宏扩展用于静态内容或模板

    【讨论】:

      【解决方案4】:

      (这更像是一个评论而不是一个答案,但我列出的代码太长了,无法评论......)

      如果您不想将代码清理为拥有vector&lt;vector&lt;int&gt;&gt; + vector&lt;vector&lt;string&gt;&gt;vector&lt;vector&lt;boost::variant&lt;int,string&gt;&gt;&gt; 或类似名称,那么您可以创建例如vector&lt;vector&lt;int&gt;*&gt;vv.push_back(&amp;v1); vv.push_back(&amp;v2); 等,以避免复制费用。

      没有办法简单迭代名为 v1v2v3 等的变量(预处理器可以做到,但它很复杂 - 如果需要,请参阅 boost 预处理器库去追求)。

      可能最容易满足于使用更简洁的便捷函数来执行 push_backs... 类似:

      vector<vector<int>>& operator<<(vector<vector<int>>& vv, vector<int>& v)
      {
          vv.push_back(v);
          return vv;
      }
      

      然后你就可以编码了……

      vv << v1 << v2 << v3 << v4 << v5;
      

      理想情况下,您应该将运算符放在匿名命名空间中,这样只有您的代码才能看到它,从而避免意外使用或其他代码中的潜在冲突。

      【讨论】:

      • 迭代{v1, v2, v3, v4, v5, v6, v7, v8} 的最简单方法是通过可变参数模板。 Boost 预处理器是 C++11 之前的 hack。
      • @MSalters:它正在生成这样的代码,这就是问题所在 - 使用预处理器,您可以创建一些 #define X 以便 X(v, 1, 1000) 替换 v1, v2, v3, v4..., v999, v1000 - 然后将输出传递给可变参数模板,将其嵌入initialiser_list 或您需要的任何内容中。这绝对是 hackish,但仍有 C++11 未触及的实用领域。
      • TBH 在这些情况下,我会使用模板元编程来定义v&lt;1&gt;, v&lt;2&gt;, ...。如果v1v2 相关的,则它们不应使用两个不同的标识符。
      • @MSalters: 轮到它了...... OP 评论说“这是它背后的想法让我烦恼,似乎必须有一个解决方案”,所以什么是明智的/最好的东西从一开始就消失了。
      【解决方案5】:

      如果您只是将string 转换为vector&lt;int&gt;,那么这个示例可能会让您大致了解如何进行操作。

      #include <iostream>
      #include <string>
      #include <vector>
      
      using namespace std;
      
      int main()
      {
          string str = "1234567890";
          vector<int> intedStr;
      
          for (size_t i = 0; i < str.length(); i++)
          {
              intedStr.push_back((int)str[i] - '0');
          }
          for (size_t i = 0; i < intedStr.size(); i++)
          {
              cout << intedStr[i] << " ";
          }
      
          system("pause");
      }
      

      注意:这不是一个安全功能。如果您想将"abcsd" 转换为vector&lt;int&gt;,会发生什么?

      【讨论】:

        猜你喜欢
        • 2021-04-04
        • 1970-01-01
        • 2023-01-30
        • 1970-01-01
        • 2020-03-04
        • 1970-01-01
        • 2022-12-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多