То, что вы хотите достичь, может быть достигнуто с помощью наследования. То есть родительский класс имеет имя переменной, которую вы хотите, чтобы ваш шаблон имел.
struct ItemNull {};
template <typename X, typename Y = ItemNull>
class Item : public X, public Y {};
template <typename T> struct HasPosition { T Position; };
template <typename T> struct HasMomentum { T Momentum; };
Item< HasPosition<float> > myItem1;
myItem1.Position = 0.123f;
Item< HasPosition<float>, HasMomentum<float> > myItem2;
myItem2.Position = 0.1f;
myItem2.Momentum = 0.2f;
Необязательный второй аргумент учитывает композицию, как показано в myItem2
. Чтобы добавить третье поле, вы можете добавить к хвосту или развернуть спереди:
template <typename T> struct HasName { T Name; };
Item <
HasPosition<float>,
Item< HasMomentum<float>, HasName<std::string> >
> myItem3;
myItem3.Position = 0.1f;
myItem3.Momentum = 0.2f;
myItem3.Name = "Adam";
Item <
Item < HasPosition<float>, HasMomentum<float> >,
HasName<std::string>
> myItem4;
myItem4.Position = 0.1f;
myItem4.Momentum = 0.2f;
myItem4.Name = "Adam";
Мое личное предпочтение отдается первому из двух методов, потому что я считаю, что это более интуитивный способ расширить его за пределы 3 полей. Синтаксис шаблона Item
, вероятно, можно упростить, используя аргументы шаблона с переменным числом аргументов.
Шаблоны Has...
могут быть сгенерированы машиной или могут быть созданы макросы, чтобы сделать добавление новых полей относительно простой задачей.
#define MAKE_HAS(X) template <typename T> struct Has##X { T X; }
MAKE_HAS(Position);
MAKE_HAS(Momentum);
MAKE_HAS(Name);