将vector <string>转换为其他类型

时间:2015-07-06 15:25:17

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

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

矢量(字符串),    串,    矢量(INT),    矢量(浮动)和    布尔

示例:

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

有人能举例说明实现它的最佳方法是什么? (没有在Boost中使用)

1 个答案:

答案 0 :(得分:0)

您无法为您的班级提供任何会员功能 这将支持你想要的两个结构:

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 &);

e是您vector<string>映射到的key map<string,vector<string>的{​​{1}}数据成员。 不是 myClass

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

myClass

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

显然,std::vector<std::string>无法解决您的要求。在 (1b)和(2b),myClass无处可见。

myClass是否有任何模板成员函数:

std::vector<std::string>

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

template<typename T> T as() const; 是否具有任何模板成员函数:

std::vector<std::string>

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

否和否。

<强>然而...

可以实施template<typename T> operator T() const; as模板成员函数 支持你提到的转换。它的签名 - 当然 - 将是:

myClass

你可以调用它:

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

我将草拟一个假设我们满意的实现 从T x = myClassInstance.as<T>("key") // (1c) 转换为:

  • std::vector<std::string>
  • std::string
  • std::vector<int>

这足以让你开始。

bool转换为std::vector<std::string> vs我会连接 std::string的元素。

要将vs转换为std::vector<std::string> vs,我会将std::vector<int>的每个元素从小数字转换为小数,如果可以的话,转换为 数字表示的整数,并返回那些整数的向量。没有 对其他政策的偏见我会抛出vs例外 当一个元素没有修剪成十进制数字时。

通过转换std::invalid_argument,我可能会选择你的意思 到std::vector<std::string>,如果我能转换它,我会随意说boolvstrue,其中任何元素都是非0,如果我可以转换为vector<int> 它到false,其中所有元素都是0。

草图:

vector<int>

这里的一个外卖点是使用#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转换为T 定义

然后,对于要转换的每种类型std::vector<std::string>,您只需要 写一个专门的定义:

U

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

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

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

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

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