【问题标题】:Convert vector<string> to other types将 vector<string> 转换为其他类型
【发布时间】:2015-09-23 19:52:04
【问题描述】:

我有一个map&lt;string,vector&lt;string&gt;&gt; 的课程。 我想给用户一个成员函数来接收与 std::vector(string) 格式不同的键的值:

向量(字符串), 细绳, 向量(整数), 向量(浮点数)和 布尔

示例:

 bool x =  (bool) myClass["dummy_boolean_type"]
 x = myClass["dummy_boolean_type"].as<bool>
 int y = (int) myClass["dummy_boolean_type"]

有人可以举个例子吗?实现它的最佳方法是什么? (在 Boost 中没有使用)

【问题讨论】:

  • myClass["dummy_boolean_type"]&lt;bool&gt; 无效...
  • 返回stringbool 对用户意味着什么?比如,bool 什么时候是真还是假?
  • 所以基本上你想在你的地图中存储不同的类型?
  • 但是对于几次阅读来说真的不清楚,但我有这个想法:作者希望 std::vector 可转换为类型:boolstd::vector&lt;int&gt;std::vector&lt;float&gt;。我说得对吗,@Shaul?

标签: c++ arrays string c++11 vector


【解决方案1】:

你不能为你的类提供任何成员函数或函数 这将支持您想要的两种结构:

T x = myClassInstance["key"].as<T>  // (1)
T x =  (T) myClassInstance["key"]   // (2)

在 (1) 的情况下,直接原因只是构造是 不合法的 C++。所以让我们假设它被替换为:

T x = myClassInstance["key"].as<T>()  // (1a)

但这无济于事,(1a)和(2)的原因是一样的:

表达式 myClassInstance["key"] 必须计算为某个对象 e 或引用以下对象返回的对象:

myClass::operator[](std::string const &);

这个evector&lt;string&gt;key 在你的 map&lt;string,vector&lt;string&gt; myClass 的数据成员。 不是myClassInstance

所以你要的是myClass 的成员函数,它将支持 结构:

T x = e.as<T> // (1b)
T x =  (T) e  // (2b)

其中estd::vector&lt;std::string&gt;

显然,您在myClass 中所做的任何事情都无法满足您的要求。在 (1b) 和 (2b),myClass 无处可见。

有没有std::vector&lt;std::string&gt;的模板成员函数:

template<typename T>
T as() const;

具有您想要的 (1b) 行为?

std::vector&lt;std::string&gt; 有没有模板成员函数:

template<typename T>
operator T() const;

具有您想要的 (2b) 行为?

没有和没有。

但是...

可以实现myClassas模板成员函数 支持您提到的转换。它的签名——当然—— 应该是:

template<typename T>
T myClass::as(std::string const & key) const;

你会像这样调用它:

T x = myClassInstance.as<T>("key")  // (1c)

我将绘制一个假设我们满足于 从std::vector&lt;std::string&gt; 到:

  • std::string
  • std::vector&lt;int&gt;
  • bool

这足以让你开始。

要将std::vector&lt;std::string&gt; vs 转换为std::string,我将连接 vs的元素。

要将std::vector&lt;std::string&gt; vs 转换为std::vector&lt;int&gt;,如果可以的话,我会将vs 的每个元素从十进制数字转换为 数字表示的整数,并返回这些整数的向量。没有 对其他政策的偏见我会抛出一个std::invalid_argument 异常 当元素不修剪为十进制数字时。

对于转换std::vector&lt;std::string&gt; 可能意味着什么,我一脸懵逼 到bool,所以我会随意说vstrue,如果我可以转换它 到一个vector&lt;int&gt;,其中任何元素都是非0并且是false,如果我可以转换的话 它到一个vector&lt;int&gt;,其中所有元素都是0。

草图:

#include <type_traits>
#include <map>
#include <vector>
#include <string>
#include <algorithm>

namespace detail {

template<typename T>
struct convert_to
{
    static T from(std::vector<std::string> const & vs) {
        static constexpr bool always_false = !std::is_same<T,T>::value;
        static_assert(always_false,
            "Calling `convert_to<T>::from` for unimplemented `T`");
        return *(T*)nullptr;
    }
};

template<>
std::string convert_to<std::string>::from(std::vector<std::string> const & vs)
{
    std::string s;
    for (  auto const & e : vs ) {
        s += e;
    }
    return s;
}

template<>
std::vector<int> 
convert_to<std::vector<int>>::from(std::vector<std::string> const & vs)
{
    auto lamb = [](std::string const & s) {
        std::size_t lastoff = s.find_last_not_of(" \t\f\v\n\r");
        int i;
        try {
            std::size_t nlen;
            i = std::stoi(s,&nlen);
            if (nlen <= lastoff) {
                throw std::invalid_argument("");
            }
        }
        catch(std::invalid_argument const & e) {
            throw std::invalid_argument(
                "Cannot convert \"" + s + "\" to int");
        }
        return i;
    };
    std::vector<int> vi;
    std::transform(vs.begin(),vs.end(),std::back_inserter(vi),lamb);
    return vi;
}

template<>
bool convert_to<bool>::from(std::vector<std::string> const & vs)
{
    auto vi = convert_to<std::vector<int>>::from(vs);
    for (auto const & i : vi) {
        if (i) {
            return true;
        }
    }
    return false;

}

} // namespace detail


struct myClass // Your class
{
    // Whatever...

    std::vector<std::string> & operator[](std::string const & key) {
        return _map[key];
    }

    template<typename T>
    T as(std::string const & key) {
        return detail::convert_to<T>::from(_map[key]);
    }

    // Whatever...

private:
    std::map<std::string,std::vector<std::string>> _map;
};

这里的一个要点是使用template<typename T> detail::struct convert_to,它具有单独的静态成员函数:

T from(std::vector<std::string> const & vs)

在默认实例化中会引发static_assert 失败 报告没有从std::vector&lt;std::string&gt; 转换为T 已定义。

然后,对于您想要转换到的每种类型 U,您只需 写一个专门的定义:

template<>
U convert_to<U>::from(std::vector<std::string> const & vs);

如您所见,构造 (1c) 将按照以下方式使用它:

template<typename T>
T myClass::as(std::string const & key) {
    return detail::convert_to<T>::from(_map[key]);
}

这是一个可以附加到草图的说明性程序:

#include <iostream>

using namespace std;

template<typename T>
static void print_vec(std::vector<T> const & v)
{
    cout << "{ ";
    for (auto const & e : v) {
        cout << e << " ";
    }
    cout << "}\n";
}

static void print_vec(std::vector<std::string> const & v)
{
    cout << "{ ";
    for (auto const & e : v) {
        cout << '\"' << e << "\" ";
    }
    cout << "}\n";
}

int main()
{
    myClass f;
    f["int_vec"] = vector<string>{"0","1 "," 2"};
    cout << "f[\"int_vec\"] = "; print_vec(f["int_vec"]); 
    f["true_vec"] = vector<string>{"0"," 1 ","0"};
    cout << "f[\"true_vec\"] = "; print_vec(f["true_vec"]);
    f["false_vec"] = vector<string>{"0"," 0","0 "};
    cout << "f[\"false_vec\"] = "; print_vec(f["false_vec"]);
    f["not_int_vec0"] = vector<string>{"0","1","2",""};
    cout << "f[\"not_int_vec0\"] = "; print_vec(f["not_int_vec0"]);
    f["not_int_vec1"] = vector<string>{"0","@","2",};
    cout << "f[\"not_int_vec1\"] = "; print_vec(f["not_int_vec1"]);
    f["not_int_vec2"] = vector<string>{"0"," 1$","2",};
    cout << "f[\"not_int_vec2\"] = "; print_vec(f["not_int_vec2"]);
    cout << "f.as<string>(\"int_vec\") = \"" 
        << f.as<string>("int_vec") << '\"' << endl;
    cout << "f.as<string>(\"true_vec\") = \"" 
        << f.as<string>("true_vec") << '\"' << endl;
    cout << "f.as<string>(\"false_vec\") = \"" 
        << f.as<string>("false_vec") << '\"' << endl;
    cout << "f.as<string>(\"not_int_vec0\") = \"" 
        << f.as<string>("not_int_vec0") << '\"' << endl;
    cout << "f.as<string>(\"not_int_vec1\") = \""
        << f.as<string>("not_int_vec1") << '\"' << endl;
    cout << "f.as<string>(\"not_int_vec2\") = \""
        << f.as<string>("not_int_vec2") << '\"' << endl;
    vector<int> va = f.as<vector<int>>("int_vec");
    cout << "f.as<vector<int>>(\"int_vec\") = "; 
    print_vec(f.as<vector<int>>("int_vec"));
    cout << boolalpha << "f.as<bool>(\"true_vec\") = " 
        << f.as<bool>("true_vec") << endl;
    cout << boolalpha << "f.as<bool>(\"false_vec\") = " 
        << f.as<bool>("false_vec") << endl;
    try {
        cout << "f.as<vector<int>>(\"not_int_vec0\")...";
        auto b = f.as<vector<int>>("not_int_vec0");
        (void)b;
    }
    catch(std::invalid_argument const & e) {
        cout << e.what() << endl;
    }
    try {
        cout << "f.as<vector<int>>(\"not_int_vec1\")...";
        auto b = f.as<vector<int>>("not_int_vec1");
        (void)b;
    }
    catch(std::invalid_argument const & e) {
        cout << e.what() << endl;
    }
    try {
        cout << "f.as<vector<int>>(\"not_int_vec2\")...";
        auto b = f.as<vector<int>>("not_int_vec2");
        (void)b;
    }
    catch(std::invalid_argument const & e) {
        cout << e.what() << endl;
    }
    // char ch = f.as<char>("int_vec"); <- static_assert fails
    return 0;
}

它输出:

f["int_vec"] = { "0" "1 " " 2" }
f["true_vec"] = { "0" " 1 " "0" }
f["false_vec"] = { "0" " 0" "0 " }
f["not_int_vec0"] = { "0" "1" "2" "" }
f["not_int_vec1"] = { "0" "@" "2" }
f["not_int_vec2"] = { "0" " 1$" "2" }
f.as<string>("int_vec") = "01  2"
f.as<string>("true_vec") = "0 1 0"
f.as<string>("false_vec") = "0 00 "
f.as<string>("not_int_vec0") = "012"
f.as<string>("not_int_vec1") = "0@2"
f.as<string>("not_int_vec2") = "0 1$2"
f.as<vector<int>>("int_vec") = { 0 1 2 }
f.as<bool>("true_vec") = true
f.as<bool>("false_vec") = false
f.as<vector<int>>("not_int_vec0")...Cannot convert "" to int
f.as<vector<int>>("not_int_vec1")...Cannot convert "@" to int
f.as<vector<int>>("not_int_vec2")...Cannot convert " 1$" to int

(gcc 5.1, clang 3.6, C++11)

【讨论】:

    猜你喜欢
    • 2014-05-16
    • 1970-01-01
    • 2013-03-15
    • 2012-03-02
    • 1970-01-01
    • 1970-01-01
    • 2014-11-19
    • 1970-01-01
    相关资源
    最近更新 更多