Is there any way to generate the name of a variable inside a class based on a template
argument?
template<class T, (someconstruct) t>
class Item {
public:
T t;
};
Item<float, "Position"> myItem;
myItem.Position = 0.123f;
Such that what I have instantiated is a variable of type T
, with the identifier t
(where t
is passed in by the programmer, i.e. Position
, so we have a T
called Position
? Or is this stretching the template meta-programming concept a little too far? :p
No, not with that syntax, but you CAN create a setup similar to what you're trying to do:
template < typename Field >
struct field_value
{
typename Field::type value;
};
template < typename Seq >
struct funky_struct : boost::mpl::inherit_linearly
<
Seq
, boost::mpl::inherit
<
field_value< boost::mpl::placeholders::_2>
, boost::mpl::placeholders::_1
>
>::type
{};
template < typename Field, typename Struct >
typename Field::type & get(Struct & s) { return static_cast< field_value<Field>& >(s).value; }
struct first_field { typedef int type; };
struct second_field { typedef char type; };
struct my_funky : funky_struct< boost::mpl::vector<first_field,second_field> > {};
...
my_funky f;
get<first_field>(f) = 23;
I leave allowing non-default construction to you. Also, with a minor amount of work this can be reflected and you can stick any amount of useful information about fields within.
No, you can't achieve this with templates. Variable names (known as "identifiers") cannot be programatically manipulated by templates. Only the preprocessor can do that.
Regardless, this seems like a bad idea. Why do you want to do this?
Something like what you want to achieve can be accomplished with inheritance. That is, the parent class has the variable name you want your template to have.
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;
The optional second argument allows for composition, as illustrated in myItem2
. To add a third field, you could add to the tail, or expand from the front:
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";
My personal preference is for the former of the two methods, because I find it to be a more intuitive way to extend it beyond 3 fields. The Item
template syntax could probably be simplified using variadic template arguments.
The Has...
templates could be machine generated or a macro could be created to make adding new fields a relatively simple task.
#define MAKE_HAS(X) template <typename T> struct Has##X { T X; }
MAKE_HAS(Position);
MAKE_HAS(Momentum);
MAKE_HAS(Name);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With