我需要在一个类中打包固定数量的任意类型的值。然后我需要能够根据类型通过交换机传递每个参数。参数的类型是基本的C类型和指向东西的指针(特定和有限数量的“东西”),所以没有什么复杂的。
“参数”类需要很轻(在空间和处理中)。
这是我需要如何使用它的一个例子:
void MyFunc( const Parameters &Params )
{
// for loop
switch( Params(0).GetType() ) {
case MY_INT_TYPE: int ValInt = Params(0).Get<int>(); ...
case MY_PTR_TO_MY_STUFF1: MyStuff1 *ValS1 = Params(0).Get<MyStuff1*>(); ...
...
}
}
Parameters MyParams(2);
MyParams.Set<int>(0, 123);
MyParams.Set<MyStuff1*>(1, &SomeClassInstance);
MyFunc( MyParams );
...
MyParams.Set<float>(0, 123.456); // The same variable in the same scope
MyParams.Set<int*>(1, &Val);
MyFunc( MyParams );
当然,我可以手动专门针对所有类型并存储在一个联合中,这就是蛮力方法。我一直在想有一种更简单的方法可以做到这一点,但无法弄清楚。我可以使用类型特征来存储类型信息,但我仍然坚持使用值。并且铸造价值不是一种选择。
任何指针(比喻指针)?
答案 0 :(得分:1)
关于上一次你的评论,我给你下一个答案:)
class ParamsProcessor
{
// custom parameter reciever for type T1
template<>
public ParamsProcessor& in<T1>(const T1& o)
{ ... }
// custom parameter reciever for type T2
template<>
public ParamsProcessor& in<T2>(T2 t2)
{ ... }
// default parameter reciever
template<class T>
public ParamsProcessor& operator in(const T& o)
{
// some generic way if the project allows
...
return *this
}
void Process()
{ ... }
};
ParamsProcessor pp;
pp.in<T1>(0,123)
.in<T2>(0,123.456)
.in("asds");
.Process();
如果每个重载都会自行处理,那么肯定会更好。 我真的希望我的答案能满足你的需求。
答案 1 :(得分:0)
如果不使用运行时多态,那么无论如何都会有一个开关。如果您将使用静态多态,则需要专门化或切换。
使用type2enum和enum2type映射的好方法:
type2enum:
// preparition
template<class T> type2enum();
#define TYPE2ENUM_SPEC(TYPE, ENUM) \
template<> type2enum<TYPE>() \
{ return ENUM; }
enum { T1enum, T2enum, T3enum }
TYPE2ENUM_SPEC(type1_t, T1enum);
TYPE2ENUM_SPEC(type2_t, T2enum);
TYPE2ENUM_SPEC(some_third_type_t, T3enum);
和向后enum2type:
// preparition
template<int Enum>
struct enum2type;
#define ENUM2TYPE_SPEC(ENUM, TYPE) \
template<> struct Enum2Type<ENUM> \
{ typedef TYPE type_t; }
// and generic macro
#define CREATE_TYPE_MAPPING(TYPE, INTEGER) \
#define TYPE2ENUM_SPEC(TYPE, INTEGER) \
#define ENUM2TYPE_SPEC(INTEGER, TYPE)
和代码示例:
我们有Type1,Type2,Type3和enum:
enum {T1, T2, T3};
CREATE_TYPE_MAPPING(Type1, T1);
CREATE_TYPE_MAPPING(Type2, T2);
CREATE_TYPE_MAPPING(Type3, T3);
用于将映射类型用于枚举:
int typeId = type2enum<Type1>();
输入或常量枚举:
typedef Enum2Type<ConstEnumType>::type_t some_t;
并且对于运行时枚举类型,您可以使用以下内容:
template<class ObjT>
void DoWithTypeIdValue(int enumValue, const ObjT& obj)
{
switch(enumValue)
{
case enumType1:
obj.do<Enum2Type<enumType1>::type_t>();
break;
case enumType2:
obj.do<Enum2Type<enumType2>::type_t>();
break;
case enumType3:
obj.do<Enum2Type<enumType3>::type_t>();
break;
default:
assert(!"Unknown type constant");
}
}
答案 2 :(得分:0)
允许摆脱开关的另一种方法是使用enum和数组函数:
enum TheTypes { T1, T2, T3, TheTypesCount};
boost::function<void (const Parameters &Params)> Processors[] = {
boost::bind(&T1::ProcessingMethod, t1Obj, _1),
boost::bind(&T2::ProcessingStaticMethod, _1),
boost::bind(RawFunction, _1)
};
这允许您用简单的构造替换侵入式缝合:
void MyFunc( const Parameters &Params )
{
// for loop
Processors[Params(0).GetType()](Params(0));
}
Congratulaions!
如果你是疯子而不是讨论下一步的方法。 如何创建静态装饰器(mixin)以自动执行以下操作:
答案 3 :(得分:0)
理想的实现方式是使用由有效的参数类型集参数化的变体类型(例如boost::variant
)。以下是如何使用变体类型来解决问题的示例:
typedef Variant<int, MyStuff1*> Parameter;
int main()
{
MyStuff1 SomeClassInstance;
Parameter MyParams[2] = { 123, &SomeClassInstance };
int ValInt = MyParams[0].Get<int>();
MyStuff1* ValS1 = MyParams[1].Get<MyStuff1*>();
}
如果您不能使用boost
,那么这是一个如何实施变体类型的示例。
#include <type_traits>
template<typename T, typename U>
struct MaxSize
{
static const size_t value = sizeof(T) > sizeof(U) ? sizeof(T) : sizeof(U);
};
struct ValueBase
{
virtual ~ValueBase()
{
}
};
template<typename T>
struct ValueGeneric : ValueBase
{
T value;
ValueGeneric(const T& value) : value(value)
{
}
};
template<typename T1, typename T2>
class Variant
{
typename std::aligned_union<MaxSize<T1, T2>::value, T1, T2>::type storage;
Variant(const Variant&); // not copyable
Variant operator=(const Variant&); // not assignable
public:
template<typename T>
Variant(const T& value)
{
new(&storage) ValueGeneric<T>(value);
}
~Variant()
{
static_cast<ValueBase*>(static_cast<void*>(&storage))->~ValueBase();
}
void Set(const T1& value)
{
SetImpl(value);
}
void Set(const T2& value)
{
SetImpl(value);
}
void Get(const T1& value)
{
this->~Variant();
new (this) Variant(value);
}
template<typename T>
bool IsA() const
{
return typeid(T) == typeid(*static_cast<const ValueBase*>(static_cast<const void*>(&storage)));
}
template<typename T>
T& Get()
{
assert(IsA<T>());
return *static_cast<T*>(static_cast<void*>(&storage));
}
template<typename T>
const T& Get() const
{
assert(IsA<T>());
return *static_cast<const T*>(static_cast<const void*>(&storage));
}
private:
template<typename T>
void SetImpl(const T& value)
{
this->~Variant();
new (this) Variant(value);
}
};
此实现仅作为示例,仅支持两种类型 - 扩展以支持更多类型相对容易。您可能希望使用template-parameter-packs和move-constructors来实现最干净,最有效的实现。