在模板特化中使用非类型模板模板参数
Using non-type template template parameter in template specialisation
我正在学习模板元编程,但在尝试实现某些目标时遇到了障碍
我认为这应该是可能的,我只是完全不知道该怎么做。
我找到了这两个我认为有些相关但并没有真正帮助的答案
假设我想表示一维和二维的点 space,那么我可以按如下方式定义它们:
template <int X>
struct Point1D {
static constexpr int x = X;
};
template <int X, int Y>
struct Point2D {
static constexpr int x = X;
static constexpr int y = Y;
};
现在我想计算两点之间的距离。一种选择是这样做:
template <typename Point1, typename Point2>
struct Distance {
static constexpr int value = Point2::x - Point1::x;
};
typedef Distance<Point1D<1>, Point1D<5>> dist;
dist::value; //4
然而,这将接受 Point2D 和定义 ::x
的任何类型
template <int X>
struct RandomType {
static constexpr int x = X;
};
typedef Distance<Point2D<5, 4>, Point1D<2>> dist2; //Should not work
typedef Distance<Point1D<5>, RandomType<6>> dist3; //Should not work either
现在,应该可以为 Point1D 和 Point2D 类型专门化 Distance,但这是我遇到困难的地方。我尝试了以下方法:
template <template <int...> typename Point1, template <int...> typename Point2>
struct Distance {};
template <>
struct Distance<Point1D, Point1D> {
/* Calculate distance between two points */
};
template <>
struct Distance<Point2D, Point2D> {
/* Calculate distance between two points in 2D space */
};
但当然现在我专注于 class 模板,而不是类型,所以这行不通。我可以将非类型参数传递给专业化:
template <template <int...> typename Point1, int N,
template <int...> typename Point2, int M>
struct Distance {};
template <int N, int M>
struct Distance<Point1D, N, Point1D, M> {
static constexpr int value = Point1D<M>::x - Point1D<N>::x;
};
typedef Distance<Point1D, 2, Point1D, 5> Two;
int x = Two::value; //3
但这违背了目的,因为我只能通过 5 和 2 的距离。我真正需要做的是能够传递任何采用一个 int N 并具有成员 X 的 class 模板,以便我可以使用任何 Point1D<N>
调用 Distance。例如。像这样:
typedef Point1D<4> p1;
typedef Point1D<6> p2;
Distance<p1, p2>::value; //2
typedef Point2D<4, 6> p3;
Distance<p3, p1>::value //Error, can't mix Point1D and Point2D
/* Something of the sort (doesn't compile) */
template<int N, int M>
struct Distance<Point1D<N>, Point1D<M>> {
static constexpr int value = Point1D<N>::x - Point1D<M>::x;
};
从概念上讲,我认为这应该可行,因为在调用 Distance 时,类型包含所有需要的信息。不知何故,通过指定 Distance 采用模板 Point1D<int N>
,我需要该函数能够调用 Point1D<N>::x
。语法是我无法弄清楚的。
如果我对问题的理解正确,解决方案是声明模板类型 Distance
但不定义它,并且仅部分专门化每对可接受的类型。例如:
template <typename, typename>
struct Distance;
由于此模板类型没有定义,尝试用任意类型实例化它都会失败,除非类型参数匹配稍后定义的部分特化。
现在部分专注于 Point1D
:
template <int ...A, int ...B>
struct Distance<Point1D<A...>, Point1D<B...>> {
static constexpr int value = Point1D<B...>::x - Point1D<A...>::x;
};
您可以通过使用相同的技术并根据需要更改计算,将其部分专门用于 Point2D
:
template <int ...A, int ...B>
struct Distance<Point2D<A...>, Point2D<B...>> {
static constexpr int value = /* ... */;
};
(请注意,int 参数包在技术上是不必要的,因为您知道每种类型使用了多少参数。但是,使用包使偏特化定义彼此保持一致 和 使得代码更易于维护。它还强制计算使用值 Point_D<...>::x
而不是仅使用模板参数的值。)
What I really need to do is able to pass any class template that takes
one int N and has a member X
为什么,你最后的尝试不错:
// Declare `Distance` as a template that takes two type parameters.
template <typename A, typename B>
struct Distance;
// Specialize 'Distance' for a special case where both type parameters
// are instances of the same template class.
template <template <int> typename AnyTemplate, int N, int M>
struct Distance<AnyTemplate<N>, AnyTemplate<M>>
{
static constexpr int value = AnyTemplate<N>::x - AnyTemplate<M>::x;
};
我正在学习模板元编程,但在尝试实现某些目标时遇到了障碍 我认为这应该是可能的,我只是完全不知道该怎么做。
我找到了这两个我认为有些相关但并没有真正帮助的答案
假设我想表示一维和二维的点 space,那么我可以按如下方式定义它们:
template <int X>
struct Point1D {
static constexpr int x = X;
};
template <int X, int Y>
struct Point2D {
static constexpr int x = X;
static constexpr int y = Y;
};
现在我想计算两点之间的距离。一种选择是这样做:
template <typename Point1, typename Point2>
struct Distance {
static constexpr int value = Point2::x - Point1::x;
};
typedef Distance<Point1D<1>, Point1D<5>> dist;
dist::value; //4
然而,这将接受 Point2D 和定义 ::x
的任何类型template <int X>
struct RandomType {
static constexpr int x = X;
};
typedef Distance<Point2D<5, 4>, Point1D<2>> dist2; //Should not work
typedef Distance<Point1D<5>, RandomType<6>> dist3; //Should not work either
现在,应该可以为 Point1D 和 Point2D 类型专门化 Distance,但这是我遇到困难的地方。我尝试了以下方法:
template <template <int...> typename Point1, template <int...> typename Point2>
struct Distance {};
template <>
struct Distance<Point1D, Point1D> {
/* Calculate distance between two points */
};
template <>
struct Distance<Point2D, Point2D> {
/* Calculate distance between two points in 2D space */
};
但当然现在我专注于 class 模板,而不是类型,所以这行不通。我可以将非类型参数传递给专业化:
template <template <int...> typename Point1, int N,
template <int...> typename Point2, int M>
struct Distance {};
template <int N, int M>
struct Distance<Point1D, N, Point1D, M> {
static constexpr int value = Point1D<M>::x - Point1D<N>::x;
};
typedef Distance<Point1D, 2, Point1D, 5> Two;
int x = Two::value; //3
但这违背了目的,因为我只能通过 5 和 2 的距离。我真正需要做的是能够传递任何采用一个 int N 并具有成员 X 的 class 模板,以便我可以使用任何 Point1D<N>
调用 Distance。例如。像这样:
typedef Point1D<4> p1;
typedef Point1D<6> p2;
Distance<p1, p2>::value; //2
typedef Point2D<4, 6> p3;
Distance<p3, p1>::value //Error, can't mix Point1D and Point2D
/* Something of the sort (doesn't compile) */
template<int N, int M>
struct Distance<Point1D<N>, Point1D<M>> {
static constexpr int value = Point1D<N>::x - Point1D<M>::x;
};
从概念上讲,我认为这应该可行,因为在调用 Distance 时,类型包含所有需要的信息。不知何故,通过指定 Distance 采用模板 Point1D<int N>
,我需要该函数能够调用 Point1D<N>::x
。语法是我无法弄清楚的。
如果我对问题的理解正确,解决方案是声明模板类型 Distance
但不定义它,并且仅部分专门化每对可接受的类型。例如:
template <typename, typename>
struct Distance;
由于此模板类型没有定义,尝试用任意类型实例化它都会失败,除非类型参数匹配稍后定义的部分特化。
现在部分专注于 Point1D
:
template <int ...A, int ...B>
struct Distance<Point1D<A...>, Point1D<B...>> {
static constexpr int value = Point1D<B...>::x - Point1D<A...>::x;
};
您可以通过使用相同的技术并根据需要更改计算,将其部分专门用于 Point2D
:
template <int ...A, int ...B>
struct Distance<Point2D<A...>, Point2D<B...>> {
static constexpr int value = /* ... */;
};
(请注意,int 参数包在技术上是不必要的,因为您知道每种类型使用了多少参数。但是,使用包使偏特化定义彼此保持一致 和 使得代码更易于维护。它还强制计算使用值 Point_D<...>::x
而不是仅使用模板参数的值。)
What I really need to do is able to pass any class template that takes one int N and has a member X
为什么,你最后的尝试不错:
// Declare `Distance` as a template that takes two type parameters.
template <typename A, typename B>
struct Distance;
// Specialize 'Distance' for a special case where both type parameters
// are instances of the same template class.
template <template <int> typename AnyTemplate, int N, int M>
struct Distance<AnyTemplate<N>, AnyTemplate<M>>
{
static constexpr int value = AnyTemplate<N>::x - AnyTemplate<M>::x;
};