我写了一个小的内部框架,它做了类似的事情:
Group<ObjectA1, ObjectA2> groupA(data);
Group<ObjectB> groupB(data);
// Compiles, as desired:
groupA.get<ObjectA1>();
groupA.get<ObjectA2>();
groupB.get<ObjectB>();
// Compilation errors (static asserts), as desired:
groupA.get<ObjectB>();
groupB.get<ObjectA1>();
groupB.get<ObjectA2>();
简而言之:可以将(可变)数量的对象组合在一起。然后,可以查询该组的类型以组类型编码的对象。对于所有其他对象,会发生编译错误。
接下来,我想扩展它具有以下能力:
// ...continued...
using GroupA = Group<ObjectA1, ObjectA2>;
using GroupB = Group<ObjectB>;
AggregateGroup<GroupA, GroupB> group(groupA, groupB);
// Compiles, as desired
group.get<ObjectA1>();
group.get<ObjectA2>();
group.get<ObjectB>();
// Compilation error, as desired:
group.get<ObjectC>();
这可以推广到由其他组组成的组。运行时解决方案很简单,但我在编译时无法解决这个问题。
问题:我们如何创建静态调度到正确成员的聚合类型的层次结构?
我当前实施的最低版本可以在http://cpp.sh/8f4l
找到答案 0 :(得分:0)
您的问题基本上是如何从ObjectA
内的GroupA
获取实际模板参数 AggregateGroup
。请参阅下面的示例(为了便于理解,我简化了您的示例)
#include <type_traits>
using namespace std;
template <class T, class T1=char>
struct Group
{
typedef T _T;
typedef T1 _T1;
};
template <class U, class U2>
class AggregateGroup
{
public:
template <class C>
void get(C x){
static_assert(is_same<C,typename U::_T>::value || is_same<C,typename U2::_T>::value, "Failed");
// You will need to add complex conditional expression here , this one is simplified than your case
}
};
using GroupA = Group<int, double>; //=== Group<ObjectA1, ObjectA2>
using GroupB = Group<bool>; //=== Group<ObjectB>
int main(){
AggregateGroup<GroupA,GroupB> g;
g.get(1); // this will compile because type of C is `int`
g.get(true); // this will compile because type of C is `bool`
// g.get(2.0); // This will NOT compile because type of C is `double`
return 0;
}
上面的诀窍是is_same<C,typename U::_T>
_T
是模板typedef
中的Group
。
如果您尝试编译行g.get<double>(2.0)
,编译器会抱怨:
main.cpp: In instantiation of 'void AggregateGroup<U, U2>::get(C) [with C = double; U = Group<int, double>; U2 = Group<bool, double>]':
main.cpp:29:15: required from here
main.cpp:17:9: error: static assertion failed: Failed
static_assert(is_same<C,typename U::_T>::value || is_same<C,typename U2::_T>::value, "Failed");
您的代码已经非常适合解决方案。唯一需要改变的是删除包装器ObjectRetriever
:
template<typename... Objects> class AggGroup;
template<typename Object, typename... Objects>
class AggGroup<Object, Objects...> : public Object, public AggGroup<Objects...>
{
public:
explicit AggGroup(Context &context)
: Object(context)
, AggGroup<Objects...>(context)
{
}
template<typename ObjectType>
bool get()
{
static_assert(
std::is_base_of<ObjectRetriever<ObjectType>, AggGroup>::value,
"Object type not in object space"
);
return static_cast<ObjectRetriever<ObjectType> &>(*this).get();
}
};
template<>
class AggGroup<>
{
public:
explicit AggGroup(Context &context)
{
}
};
尝试以下用法
using GroupA = ObjectGroup<ObjectA>;
using GroupB = ObjectGroup<ObjectB, ObjectC>;
AggGroup<GroupA, GroupB> group(context);
group.get<int>(); // not compile
group.get<ObjectB>(); // OK
完整代码here。