Я узнаю о шаблонном метапрограммировании и столкнулся с проблемой, пытаясь достичь чего-то, что, по моему мнению, должно быть возможным, я просто не могу понять, как это сделать.
Я нашел эти два ответакоторые, как я думал, были в некоторой степени связаны, но не помогли
Допустим, я хочу представить точки в 1D и 2D пространстве, тогда я могу определить их следующим образом:
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
Теперь должна быть возможность специализировать Distance для Point1D. и Point2D, но я застрял здесь. Я попробовал следующее:
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 */
};
Но, конечно, сейчас я специализируюсь на шаблоне класса, а не на типе, так что это не будет работать. Я могу передать нетипизированные параметры специализации как таковые:
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, так что я могу вызвать Distance с любым Point1D<N>
. Например, что-то вроде этого:
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
. Синтаксис - это то, что я не могу понять.