Nathanael C.
Nathanael C.

Reputation: 73

Set private attribute depending on template's typename

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

Answers (3)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

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

phantom
phantom

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

R Sahu
R Sahu

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

Related Questions