I am trying to wrap a c-style variant in a library. It uses a type enum
, which I mean to fill using templates.
A simplified version looks roughly like this:
enum Type
{
Type_Int,
Type_Double,
Type_String
};
template<typename T>
Type typeId();
template<> Type typeId<int>() { return Type_Int; }
template<> Type typeId<double>(){ return Type_Double; }
template<> Type typeId<const char*>() { return Type_String; }
template<> Type typeId<char[10]>() { return Type_String; }
// not allowed
// template<int N> Type typeId<char[N]>() { return Type_String; }
https://godbolt.org/z/3GsKv6PEn
I can recognize char[10]
just fine, but I want to make a general case of char[N]
, which is not allowed. So how would I go about recognizing all char[N]
types?
ps. It is embedded, so I prefer not to use std::string
where possible.
You can't partially specialize a functions. But you can partially specialize class or struct.
So to resolve this do template logic in a class and then use it in a function:
enum Type {
Type_Int,
Type_Double,
Type_String,
};
namespace detail {
template <typename T>
class TypeId;
template <>
class TypeId<int> {
public:
static constexpr Type value = Type_Int;
};
template <>
class TypeId<double> {
public:
static constexpr Type value = Type_Double;
};
template <>
class TypeId<const char*> {
public:
static constexpr Type value = Type_String;
};
template <int N>
class TypeId<const char[N]> {
public:
static constexpr Type value = Type_String;
};
}
template <typename T>
constexpr Type typeId()
{
return detail::TypeId<T>::value;
}
static_assert(typeId<int>() == Type_Int);
static_assert(typeId<double>() == Type_Double);
static_assert(typeId<const char*>() == Type_String);
static_assert(typeId<const char[2]>() == Type_String);
static_assert(typeId<const char[10]>() == Type_String);
https://godbolt.org/z/4zfb47Mvx
To make this more resistant to cv-qualifiers type variations you can use std::remove_cvref_t : https://godbolt.org/z/esGf4Wc8h