class 专业化,没有用作专业化模板参数的 class 的模板参数

class specialization, without the template arguments of the class that is used as template argument for specialization

我目前在一个地理图书馆工作,我想要一个 general-purpose 向量 class 可以用于 lat/lng 点和投影点。

lat/lng 点的方向由方位角和长度描述,投影 space 中的方向由二维向量和长度描述。

所以 class 应该是这样的:

template <typename T>
struct vector {
    direction_t direction;
    lenght_t length;
};

lat/lng点定义为:

template <angle_unit T>
struct latlng {
  …
};

点定义为:

template <typename projection_t,typename T = double>
struct point {
   …
};

所以我最初的想法是将direction_t定义为direction_trait<T>::direction_type direction:

template <typename T>
struct vector {
    using direction_t = direction_trait<T>::direction_type;

    direction_t direction;
    lenght_t length;
};

并且对 latlngpoint 都有 direction_trait 的特化,而无需为 latlnglatlng 的每个可能的模板参数定义特化point

我怎么能有这样的东西:

template <typename T>
struct direction_trait;


template <latlng>
struct direction_trait {
    using direction_t = double;
};

我不想将与方向相关的信息添加到定义了 latlngpoint 的 header。

(我在写这个问题的时候已经想出了解决方法,但是如果没有那个帮手有更优雅的方法解决这个问题class我会很乐意知道了)

我想出的解决方案如下,使用仅用于专业化的 class 的声明,以及对 class 的 class 的引用] latlng(点)的主体,使用 using trait = latlng_trait;。该别名随后由矢量使用并获取方向类型。

经纬度 class:

struct latlng_trait; // a declaration of a class solely used for template specialization

template <angle_unit T>
struct latlng {
    using trait = latlng_trait;

    …
}

latlng 的专业化:

template <>
struct direction_trait<latlng_trait> {
    using direction_t = double;
};

向量:

template <typename T>
struct vector {
    typename direction_trait<typename T::trait>::direction_t direction;
};

以下随心所欲:

#include <type_traits> // only for is_same_v in the tests

using angle_unit = int; // just so it compiled
template <angle_unit T>
struct latlng {
};

template <typename projection_t, typename T = double>
struct point {
};

template<typename T>
struct direction_trait;

template<angle_unit T>
struct direction_trait<latlng<T>> {
    using direction_type = double;
};

template<typename projection_t, typename T>
struct direction_trait<point<projection_t, T>> {
    using direction_type = T; // Or whatever you want
};

template <typename T>
struct vector {
    using direction_t = typename direction_trait<T>::direction_type;

    direction_t direction;
};

// Usage
static_assert(std::is_same_v<vector<latlng<5>>::direction_t, int>);
static_assert(std::is_same_v<vector<point<long>>::direction_t, double>);
static_assert(std::is_same_v<vector<point<long, float>>::direction_t, float>);