I am using a library which define various constants, like JQX_TYPE_INT
, JQX_TYPE_LONG
, JQX_TYPE_DOUBLE
etc.
My problem is to relate values to c types.
For example, in order to have a function which works for various types i have to implement a copy of the same code, differing only in the constant, for every c -type, e.g.:
myObj *createObject(int iSize, int iDummy) {
int iRealSize = calcEffectiveSize(iSize, JQX_TYPE_INT);
return new myObj(iRealSize);
}
myObj *createObject(int iSize, double dDummy) {
int iRealSize = calcEffectiveSize(iSize, JQX_TYPE_DOUBLE);
return new myObj(iRealSize);
}
// ... same for float char, etc.
That is, apart from having to implement the same code several times, i have to use a dummy variable in order to use the constant related to the c -type.
Is there some sort of template approach to do something like
template<tyepename T>
struct jqx_type {
static const int type;
// ... template magic
}
template<<typename T>
myObj *createObject(int iSize) {
int iRealSize = calcEffectiveSize(iSize, jqx_type<T>::type);
return new myObj(iRealSize);
}
I tried this
template<typename T>
struct jqx_type {
static const int type = JQX_TYPE_NONE;
};
template<typename T=int>
struct jqx_type {
static const int type = JQX_TYPE_INT;
};
template<typename T=long>
class jqx_types {
static const int type = JQX_TYPE_LONG;
};
But this doesn't even compile.
Is there a way to achieve what i intend to do?
CodePudding user response:
Here:
template<typename T> struct jqx_type { static const int type = JQX_TYPE_NONE; }; template<typename T=int> struct jqx_type { static const int type = JQX_TYPE_INT; }; template<typename T=long> class jqx_types { static const int type = JQX_TYPE_LONG; };
You redeclared the same template several times with different default arguments. What you actually want is one template with different specializations:
template<typename T>
struct jqx_type {
static const int type = JQX_TYPE_NONE;
};
template<>
struct jqx_type<int> {
static const int type = JQX_TYPE_INT;
};
template<>
struct jqx_types<long> {
static const int type = JQX_TYPE_LONG;
};
PS: type
is very common name for member type aliases. I would not use it for an int
. Maybe type_selector
is a better name.
CodePudding user response:
I would go with a much simpler
myObj *createObject(int iSize, int jqx_type) {
return new myObj(calcEffectiveSize(iSize, jqx_type));
}
myObj *o = createObject(16, JQX_TYPE_DOUBLE);
or if it needs to be constexpr
template <int jqx_type>
myObj *createObject(int iSize) {
return new myObj(calcEffectiveSize(iSize, jqx_type));
}
myObj *o = createObject<JQX_TYPE_DOUBLE>(16);
but lets assume you need the actual type it could be something like this:
template <typename T>
struct MyObj {
MyObj(std::size_t size, int jqx_type)
: iSize{calcEffectiveSize(size, jqx_type)} { ... }
MyObj * create(std::size_t size) {
constexpr int jqx_type = []() {
if constexpr (std::is_same_v<T, int>) return JQX_TYPE_INT;
if constexpr (std::is_same_v<T, double>) return JQX_TYPE_DOUBLE;
}();
return new MyObj{iSize, jqx_type};
}
};
or if you do want to go the type traits route then you have to specialize the template struct like this:
template<typename T>
struct jqx_type {
static const int type = JQX_TYPE_NONE;
};
template<>
struct jqx_type<int> {
static const int type = JQX_TYPE_INT;
};
template<>
struct jqx_types<long> {
static const int type = JQX_TYPE_LONG;
};
But that's as much code as specializing the createObject function.
PS: you can match and mix ideas, too. E.g. template createObject function with the if constexpr
lambda.