我有一个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中使用)
答案 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>
,如果我能转换它,我会随意说bool
是vs
到true
,其中任何元素都是非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)