将矢量转换为<string>其他类型的

Convert vector<string> to other types

本文关键字:string gt 其他 类型 lt 转换      更新时间:2023-10-16

我有一个map<string,vector<string>>类。我想给用户一个成员函数,以接收与 std::vector(字符串( 不同格式的键的值:

向量(字符串(, 字符串 向量, 向量(浮点数(和 布尔

例:

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

有人可以举一个例子,实现它的最佳方法是什么?(在加速中不使用(

不能为类提供任何一个或多个成员函数这将支持您想要的两个构造:

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

ekey映射到的vector<string> map<string,vector<string> myClass的数据成员。它不是 myClassInstance .

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

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

其中estd::vector<std::string>.

显然,您在myClass中无法满足您的要求。在(1b(和(2b(,myClass无处可见。

std::vector<std::string>有没有模板成员函数:

template<typename T>
T as() const;

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

std::vector<std::string>是否有任何模板成员函数:

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<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>可能意味着什么,我被宠坏了到bool,所以我会武断地说vstrue如果我能转换它到任何元素都不是 0 并且falsevector<int>,如果我可以转换它到一个所有元素均为 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(" tfvnr");
        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<std::string>转换为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(