从 c++ 中的字符串向量创建一个元组

Create a tuple from a vector of strings in c++

本文关键字:一个 元组 创建 c++ 字符串 向量      更新时间:2023-10-16

我有一个字符串向量,每个向量都是将std::to_string应用于一些基本数据类型(例如char,int,double(的结果。我想要一个函数来撤消到适当类型的元组中。

我有一个简单的函数模板来反转 std::to_string:

template<typename T>
T from_string(std::string s)
{
}
template<>
int from_string<int>(std::string s)
{
return std::stoi(s);
}
template<>
double from_string<double>(std::string s)
{
return std::stod(s);
}
//... and more such specializations for the other basic types

我想要一个这样的函数:

template<typename... Ts>
std::tuple<Ts> undo(const std::vector<std::string>>& vec_of_str)
{
// somehow call the appropriate specializations of from_string to the elements of vector_of_str and pack the results in a tuple. then return the tuple.     
}

该函数的行为应如下所示:

int main()
{
auto ss = std::vector<std::string>>({"4", "0.5"});
auto tuple1 = undo<int, double>(ss);
std::tuple<int, double> tuple2(4, 0.5);
// tuple1 and tuple2 should be identical. 
}

我认为我必须"迭代"Ts中的参数(也许正确的术语是"解包"(,调用前面的函数,为每个函数from_string,然后将每个from_string应用程序的结果打包到一个元组中。我已经看到(并使用(解压缩模板参数包的示例 - 它们通常是递归的(但不是以函数调用自身的通常方式(,但我看不出如何做其余的。

一个例子:

#include <vector>
#include <string>
#include <tuple>
#include <cassert>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/trim.hpp>
template<class... Ts, size_t... Idxs>
std::tuple<Ts...>
parse(std::vector<std::string> const& values, std::index_sequence<Idxs...>) {
return {boost::lexical_cast<Ts>(boost::algorithm::trim_copy(values[Idxs]))...};
}
template<class... Ts>
std::tuple<Ts...> undo(std::vector<std::string> const& values) {
assert(sizeof...(Ts) == values.size());
return parse<Ts...>(values, std::make_index_sequence<sizeof...(Ts)>{});
}
int main() {
auto ss = std::vector<std::string>({"4", "0.5"});
auto tuple1 = undo<int, double>(ss);
std::tuple<int, double> tuple2(4, 0.5);
std::cout << (tuple1 == tuple2) << 'n';
assert(tuple1 == tuple2);
}

如果字符串值不包含前导和/或尾随空格,则可以删除对boost::algorithm::trim_copy的调用。它之所以存在,是因为boost::lexical_cast在空格上失败。


如果没有boost::lexical_cast,您将需要重新实现它,例如:

template<class T> T from_string(std::string const& s);
template<> int      from_string<int>(std::string const& s)    { return std::stoi(s); }
template<> double   from_string<double>(std::string const& s) { return std::stod(s); }
// And so on.
template<class... Ts, size_t... Idxs>
std::tuple<Ts...>
parse(std::vector<std::string> const& values, std::index_sequence<Idxs...>) {
return {from_string<Ts>(values[Idxs])...};
}

对于 C++11 -- 如果您没有 C++14(Maxim 解决方案需要(,或者如果您想学习实现递归可变参数模板,则很有用:

#include <string>
#include <vector>
#include <tuple>
#include <cassert>
template <std::size_t N, typename T>
struct Undo
{
static void f(T& tuple, const std::vector<std::string>& vec_of_str)
{
Undo<N - 1, T>::f(tuple, vec_of_str);
std::get<N - 1>(tuple) = from_string<
typename std::tuple_element<N - 1, T>::type
>(vec_of_str[N - 1]);
}
};
template <typename T>
struct Undo<0, T>
{
static void f(T&, const std::vector<std::string>&)
{
}
};
template <typename... Ts>
std::tuple<Ts...> undo(const std::vector<std::string>& vec_of_str)
{
assert(vec_of_str.size() == sizeof...(Ts));
std::tuple<Ts...> ret;
Undo<sizeof...(Ts), std::tuple<Ts...>>::f(ret, vec_of_str);
return ret;
}