简体   繁体   English

模板的编译时类型名别名

[英]Compile-time typename aliasing for templates

In my collision/physics engine, I know what spatial partitioning method I'm using at runtime, thanks to templates. 在我的碰撞/物理引擎中,由于有了模板,我知道运行时正在使用哪种空间分区方法。 I'm trying to create a generic Query class that allows me to perform the same queries on any spatial partitioning method. 我正在尝试创建一个通用的Query类,该类允许我对任何空间分区方法执行相同的查询。 Every spatial partitioning method implements its own version of the query, but the interface is the same. 每种空间分区方法都实现其自己的查询版本,但是接口是相同的。

The problem is that the user has to specify the spatial partitioning type , the query type of the spatial partitioning type , and the query mode of the spatial partitioning type . 问题在于,用户必须指定空间分区类型空间分区类型查询类型以及空间分区类型查询模式

If the user were to change its spatial partitioning method, all the existing code would break. 如果用户要更改其空间分区方法,则所有现有代码都会中断。

Is there a way to allow the user to only specify the spatial partitioning type , a generic query type , and a generic query mode and have some kind of aliasing so that the correct type (relative to the spatial partitioning type) is selected automatically? 有没有一种方法允许用户仅指定空间分区类型 ,通用查询类型和通用查询模式,并具有某种别名,以便自动选择正确的类型(相对于空间分区类型)?

I've tried using (C++11 typedef ) and decltype along with partial specializations, but I couldn't find a correct way to write the code and I never got it to compile/work. 我已经尝试过using (C ++ 11 typedef )和decltype以及部分专业化知识,但是我找不到正确的编写代码的方法,而且我从未得到过它来进行编译/工作。

I can only think about using virtual methods and a base class - but that seems unnecessary since I "know" the types at compile-time. 我只能考虑使用virtual方法和基类-但这似乎是不必要的,因为我在编译时就“知道”了这些类型。


Current code: 当前代码:

 // Query.h
 template<class T, class U, class V>
 Query<T, U, V> getQuery() { return Query<T, U, V>(getSpatial<T>()); } 

 // Example.cpp (user project)
 getQuery<Grid, GridQueryType::Point, GridQueryMode::All>(); 
 getQuery<QuadTree, QuadTreeQueryType::Point, QuadTreeQueryMode::All>();

Desired code (not valid): 所需代码(无效):

 // Query.h
 namespace Type { struct Point; }
 namespace Mode { struct All; }
 template<class T, class U, class V>
 Query<T, typename T::U, typename T::V> getQuery() 
 { 
      return Query<T, typename T::U, typename T::V>(getSpatial<T>()); 
 } 

 // Grid.h
 using Type::Point = GridQueryType::Point;
 using Mode::All = GridQueryMode::All;

 // QuadTree.h
 using Type::Point = QuadTreeQueryType::Point;
 using Mode::All = QuadTreeQueryMode::All;

 // Example.cpp (user project)
 getQuery<Grid, Type::Point, Mode::All>(); // actually uses GridQueryType::Point and GridQueryMode::All!
 getQuery<QuadTree, Type::Point, Mode::All>(); // actually uses QuadTreeQueryType::Point and QuadTreeQueryMode::All!

Real code also passes typename... TArgs to allow query-type-specific parameters - I excluded it from the example for space reasons. 实际代码还会传递typename... TArgs以允许特定于查询类型的参数-由于空间原因,我从示例中排除了它。

If there is a directly relationship from your first template parameter to the second and the third it seems the latter ones shouldn't be taken as template parameters but be determined from a type-map: 如果您的第一个模板参数与第二个和第三个模板有直接关系,则似乎不应将后者作为模板参数,而应通过类型映射确定:

template <typename> struct TypePoint;
template <typename> struct ModeAll

template <> struct TypePoint<Grid> { typedef GridQueryType::Point type; };
template <> struct ModeAll<Grid>   { typedef GridQueryMode::All type; };

getQuery<Grid>();

At least, using a typemap as above you could define default values for the arguments. 至少,使用上述类型映射,可以为参数定义默认值。 In case additional arguments are meant to follow, you could basically group the three first arguments together with their defaults into a type which is passed instead, eg: 如果要使用其他参数,则基本上可以将前三个参数及其默认值归为一个类型,该类型将被传递,例如:

template <typename T,
          typename P = typename TypePoint<T>::type,
          typename M = typename ModeAll<T>::type>
struct QueryParameters {
    typedef T type;
    typedef P point_type;
    typedef M mode_type;
};
getQuery<QueryParemeters<Grid>, Other, Paremters>();

I think the solution here is a combination of template specialization and template template parameters. 我认为这里的解决方案是模板专业化和模板模板参数的组合。

Firts we define the different types of query: 首先我们定义不同类型的查询:

namespace Type
{
    template<typename SPATIAL_PARTITION>
    struct Point;
}

namespace Mode
{
    template<typename SPATIAL_PARTITION>
    struct All;
}

Next, in each spatial partitionning implementation, we specialize the types and modes. 接下来,在每个空间分区实现中,我们都专门化类型和模式。 For example, in Quadtree.h: 例如,在Quadtree.h中:

namespace Type
{
    template<>
    struct Point<Quadtree>
    {
        /* ... implementation here ... */
    }
}

namespace Mode
{
    template<>
    struct All<Quadtree>
    {
        /* ... implementation here ... */
    }
}

Finally, in the query we use template template parameters to specify the mode and type: 最后,在查询中,我们使用模板模板参数来指定模式和类型:

template<typename SPATIAL_PARTITION, template<typename> class TYPE , template<typename> class MODE>
void getQuery()
{
    using type = TYPE<SPATIAL_PARTITION>;
    using mode = MODE<SPATIAL_PARTITION>;
}

I would go in another direction. 我会朝另一个方向前进。 As you have got template function you could use type deduction. 有了模板功能后,就可以使用类型推导了。 Return object depends on function template parameters. 返回对象取决于功能模板参数。 So instead of alias you could typedef returns types. 因此,您可以使用typedef返回别名来代替别名。

// Grid.h
//using Type::Point = GridQueryType::Point;
//    using Mode::All = GridQueryMode::All;
typedef Query<Grid, GridQueryType::Point, GridQueryMode::All> T_one;

// QuadTree.h
//using Type::Point = QuadTreeQueryType::Point;
//using Mode::All = QuadTreeQueryMode::All;

typedef Query<Grid, QuadTreeQueryType::Point, QuadTreeQueryMode::All> T_two;

// Example.cpp (user project)
//getQuery<Grid, Type::Point, Mode::All>(); // actually uses GridQueryType::Point and     
//getQuery<QuadTree, Type::Point, Mode::All>();
T_one t = getQuery();
T_two t2 = getQuery();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM