我正在尝试做一些我认为最初应该微不足道的事情,但遇到了关于我应该如何理想地构建它的设计问题。我想创建一个存储一堆参数的键值对映射。这里的“key”始终是一个字符串。但是该值可以是 int、double、string 或 char。我有枚举来定义类型:
typedef enum {INT = 0, DOUBLE, STRING, CHAR} val_type;
我正在考虑将其构造为 map vector
std::vector<std::map<std::string, T>> params;
解决这个问题最原则的方法是什么?
编辑:更新了 vector 声明。
最佳答案
我还有 15 分钟时间。传入标记 union 。不如boost::variant
,我可能不会真正编译它,但它应该可以帮助您开始。
template<size_t S>
using size = std::integral_constant<std::size_t, S>;
template<bool b>
using bool_t = std::integral_constant<bool, b>;
template<size_t...Ss>
struct max_size:size<0>{};
template<size_t S0, size_t...Ss>
struct max_size:size<(std::max)(S0, max_size<Ss...>{}())>{};
template<class...Ts>
struct max_alignof : max_size< alignof(Ts)... >{};
template<class...Ts>
struct max_sizeof : max_size< sizeof(Ts)... >{};
template<class X>struct tag{using type=X;};
template<class...>struct types{using type=types;};
template<class Tag>using type_t=typename Tag::type;
template<class T, class Types>
struct index_of {};
template<class T, class...Ts>
struct index_of<T, types<T,Ts...>>:size<0>{};
template<class T, class T0, class...Ts>
struct index_of<T, types<T0,Ts...>>:size<
index_of<T, types<Ts...>>{}+1
>{};
template<class X>
struct emplace_as {};
template<class F, class...Ts>
void invoke( types<Ts...>, void* p, F&& f, size_t i ) {
auto* pf = std::addressof(f);
using operation=void(*)(decltype(pf), void*);
operation table[]={
+[](decltype(pf), void* p){
Ts* pt = static_cast<Ts*>(p);
std::forward<F>(*pf)( *pt );
}...
};
table[i]( pf, p );
}
template<class T0, class...Ts>
struct one_of {
std::aligned_storage< max_sizeof<T0, Ts...>{}, max_alignof<T0, Ts...>{} > data;
size_t index = -1;
using my_types = types<T0, Ts...>;
template<class T>
using sfinae_my_type = tag< size<index_of<X,my_types>{}> >;
one_of():one_of(emplace_as<T0>{}) {}
// brace construction support for only the first type:
one_of(T0&&t0):one_of(emplace_as<T0>{}, std::move(t0)) {}
template<class X, class...Args, class=sfinae_my_type<X>>
one_of(emplace_as<X>, Args&&... args){
emplace( emplace_as<X>{}, std::forward<Args>(args)... );
}
template<class X, class=sfinae_my_type<std::decay_t<X>>>
one_of(X&& x) {
emplace_as(std::forward<X>(x));
}
template<class X, class=sfinae_my_type<X>>
X* get() {
if (index_of<X, my_types>{}==index) {
return static_cast<X*>(&data);
} else {
return nullptr;
}
}
template<class X, class=sfinae_my_type<X>>
X const* get() const {
if (index_of<X, my_types>{}==index) {
return static_cast<X const*>(&data);
} else {
return nullptr;
}
}
template<class X, class=sfinae_my_type<std::decay_t<X>>>
void emplace(X&& x) {
emplace_as<std::decay_t<X>>{}, std::forward<X>(x));
}
template<class X, class...Args, class=sfinae_my_type<X>>
void emplace( emplace_as<X>, Args&&...args ) {
destroy();
new(&data) X(std::forward<Args>(args)...);
index = index_of<X, list<T0, Ts...>>{};
}
template<class F>
void my_invoke(F&& f) {
my_invoke( std::forward<F>(f), index );
}
template<class F>
void apply(F&& f) {
invoke( my_types{}, &data, std::forward<F>(f), index );
}
void destroy() {
if (index != -1) {
apply([&](auto&& x){
using X=std::decay_t<decltype(x)>;
index = -1;
x.~X();
});
};
}
one_of& operator=(one_of const& rhs){
if (this == &rhs) return *this;
destroy();
rhs.apply( [&](auto const& x) {
using X=std::decay_t<decltype(x)>;
emplace( emplace_as<X>{}, decltype(x)(x) );
} );
return *this;
}
one_of& operator=(one_of&& rhs){
if (this == &rhs) return *this;
destroy();
rhs.apply( [&](auto & x) {
using X=std::decay_t<decltype(x)>;
emplace( emplace_as<X>{}, std::move(x) );
} );
return *this;
}
~one_of(){destroy();}
};
这是标记 union 类型的快速草图。
存储 one_of<int, double, std::string, char>
作为您的T
。通过 apply
访问传入一个具有每个覆盖的函数,或 get<T>
.
上面是C++14,因为它更容易。它不包括apply
它具有返回值,同样是因为它使事情变得更容易。两者都可以补救,但这需要工作,实际上,您应该看看如何 boost
这样做而不是使用上面的。
关于c++ - C++11 中的模板化映射 vector ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30677255/