Reputation: 73
Context:
We're trying to set up a class template, named Operand, which could take several types as its typename T
. Those are defined in the following enum:
enum eOperandType {
INT8
INT16,
INT32,
FLOAT,
DOUBLE
};
Those correspond to the types defined in <cstdint>
, that is, int8_t, int16_t
, and so on.
The constructor must be Operand(std::string const & value);
.
template<class T>
class Operand : public IOperand
{
public:
Operand(std::string const & value)
{
std::stringstream ss(value);
ss >> _value;
//_type = ??? ;
}
[...]
private:
Operand(void){}
eOperandType _type;
T _value;
};
The interface IOperand is nothing important here, just some prototypes for operator overloads.
Question:
What's the best way to set the _type
attribute? The easy way would be to just write several if/else if
with typeid
or something close to that, but I feel like that would be pretty dirty. Furthermore, I just think that using typeid
inside of a template just means that you're doing something wrong somewhere... right?
Upvotes: 4
Views: 522
Reputation: 275750
template<class...>struct types{using type=types;};
template<class E, E...es>
using enums=std::integer_sequence<E,es...>;
template<class types, class T, class enums>
struct pick;
template<class T0, class...Ts, class T, class E, E e0, E...es>
struct pick< types<T0, Ts...>, T, enums<E,e0,es...>>:
pick< types<Ts...>, T, enums<E,es...>>
{};
template<class T0, class...Ts, class E, E e0, E...es>
struct pick< types<T0, Ts...>, T0, enums<E,e0,es...>>:
std::integral_constant<E,e0>
{};
then
using c_types = types<int8_t, int16_t, int32_t, float, double>;
using e_types = enums<eOperandType, INT8, INT16, INT32, FLOAT, DOUBLE>;
and in the class itself:
static const eOperandType _type = pick<c_types, T, e_types>::value;
this won't work with many 100s of types.
Here I made it static const
, because it cannot vary, so why let it?
Upvotes: 0
Reputation: 3342
You can use template overloads. If you specialize the template parameter for each of the types you can set a specific parameter for you can have a specific value in the specialized template. You can then use that value for the _type
attribute. So if you do something like this
template<typename _Ty> struct OperandSelector;
template<> struct OperandSelector<int8_t> {
static const eOperandType value = INT8;
}
and then create another specialization for each of the values you want to use, in your case INT16
, INT32
, FLOAT
and DOUBLE
. To set the value of _type
you would then assign to it with the value of OperandSelector<T>::value
like this
_type = OperandSelector<T>::value;
this approach would allow the selection to be done at compile time and make selecting the value a simple copy.
Upvotes: 4
Reputation: 206697
Use a helper class to deduce the value of _type
.
template <typename T> struct OperandType;
template <> struct OperandType<int8_t>
{
static const eOperandType t = INT8;
};
template <> struct OperandType<int16_t>
{
static const eOperandType t = INT16;
};
etc.
and use it as:
Operand(std::string const & value) : type_(OperandType<T>::t)
{
...
}
PS
Given that you can deduce the value of type_
any time you need it, does it make sense to store it as a member variable?
Upvotes: 5