【问题标题】:C++ check if element is std::vectorC++ 检查元素是否为 std::vector
【发布时间】:2012-10-18 23:26:12
【问题描述】:

我想遍历一个向量并检查元素是向量还是字符串。我还需要一种将不同的向量传递给函数的方法。 像这样的:

using namespace std;
string toCustomString(<some vector> vec) {
    string ret = "";
    for(size_t i = 0; i < vec.length(); ++i) 
        if (vec[i] == %vector%)
            ret += toCustomString(vec[i]);
        else //if type of vec[i] is string
            ret += "foo"+vec[i]+"bar";
    }
    return ret;
}
  • 嗯,首先我需要知道如何正确检查 vec[i] 是否为 std::vector

  • 然后我需要知道如何定义函数的参数以接受任何类型的(多维)向量

【问题讨论】:

  • 查找运行时类型标识 (RTTI) 和 typeid 关键字
  • C++ std::vector 只能包含一种静态类型的项目:vector&lt;string&gt; 的每个元素都是字符串,vector&lt;vector&lt;T&gt; &gt; 的每个元素都是vector&lt;T&gt;
  • 这是你在动态类型语言中会做的事情。在像 C++ 这样具有静态类型的语言中,这将非常复杂。发布您实际尝试完成的工作,有人可能会提出一个可以使用静态类型语言的解决方案。

标签: c++ types vector


【解决方案1】:

std::vector 只能包含一种类型——即std::vector&lt;T&gt; 中的T,可以通过成员value_type 访问。

您可能正在寻找的是模板专业化:

template<typename T>
string toCustomString(std::vector<T> vec) {
    // general case
}

template<>
string toCustomString<std::string>(std::vector<std::string> vec) {
    // strings
}

(如果你想对所有向量进行部分特化,那么你需要将它提升到一个结构中)

如果您真的想在向量中同时存储字符串和向量,请查看 Boost.Variant 和 Boost.Any

【讨论】:

    【解决方案2】:

    通常,您的&lt;some vector&gt; vec 将具有类型either vector&lt;string&gt; vector&lt;vector&lt;string&gt;&gt;,例如。

    为了声明变量,你需要它的类型,而且它的类型也准确地指定了它存储的内容。

    现在,您可以使用 Boost.Variant 解决此问题(或滚动您自己的可区分联合),如下所示:

    typedef boost::variant<std::string, std::vector<std::string>> Vec_of_StringOrVec;
    

    但 Dirk Holsopple 说得对,这不是惯用的 C++,您最好寻找不同的方法。

    【讨论】:

    • 原则上没有什么可反对歧视性工会的。对于 C++,我也不会称它们为“不惯用的”。适当的“封闭”代数数据类型在任何语言中都有其价值;在 OO 语言中,使用公共基类的派生实例可能更惯用,但这并不总是最佳的。
    • 是的 - 我想我的意思是非基于继承的运行时多态性不是很 C++... 更常见的是为不相关的类型和/或虚拟选择编译时多态性调度运行时。它没有任何问题,但从问题中我无法判断是否有更惯用的替代方法
    【解决方案3】:

    正如大家所说,C++ 中的向量只有一种类型。没有必要也没有必要依次检查每个元素的类型,这也很好,因为没有办法做到这一点。相反,您要做的是在参数类型上重载函数。像这样的:

    string toCustomString(const string &str) {
        return "foo" +str + "bar";
    }
    
    template <typename T>
    string toCustomString(const std::vector<T> &vec) {
        string ret;
        for(size_t i = 0; i < vec.size(); ++i) 
            ret += toCustomString(vec[i]);
        return ret;
    }
    

    现在,如果有人将vector&lt;string&gt; 传递给toCustomString,那么调用toCustomString(vec[i]) 将选择toCustomString(const string &amp;str) 重载。

    如果有人将vector&lt;int&gt; 传递给toCustomString,则代码将无法编译,因为(当前)没有toCustomString(int) 重载[*]。

    如果有人将vector&lt;vector&lt;string&gt;&gt; 传递给toCustomString,那么toCustomString(vec[i]) 将传递vector&lt;string&gt;,见上文。

    在所有三种情况下,不同 toCustomString 函数被调用。第一种情况是toCustomString&lt;string&gt;(const vector&lt;string&gt;&amp;),这是toCustomString 模板与第三种情况toCustomString&lt;vector&lt;string&gt;&gt;(const vector&lt;vector&lt;string&gt;&gt;&amp;) 的不同实例化。中间情况尝试实例化toCustomString&lt;int&gt;,但由于toCustomString(v[i]) 与它所知道的任何函数都不匹配而失败。

    所有这些都是在编译时确定的。模板的重点是创建多个函数(或类),它们之间有特定的差异。在这种情况下,区别在于传入的向量类型。

    [*] 这似乎符合您的说法,即vec[i] 必须是要么 一个向量 一个字符串,而不是任何第三个选项。例如,如果您希望 vector&lt;something_else&gt; 的返回值为空,则可以添加一个包罗万象的模板:

    template <typename T> 
    string toCustomString(const T &) { 
        return string(); 
    }
    

    当然,您可以为您想要处理的任何其他类型添加更多重载。

    【讨论】:

      猜你喜欢
      • 2015-02-14
      • 1970-01-01
      • 2019-12-29
      • 2010-10-25
      • 2017-03-23
      • 1970-01-01
      • 2020-11-09
      • 2018-01-11
      相关资源
      最近更新 更多