静态分派以使用聚合类型的层次结构更正成员方法

时间:2016-04-28 12:17:22

标签: c++ c++11

我写了一个小的内部框架,它做了类似的事情:

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

找到

1 个答案:

答案 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