I have a class template for which I want to introduce several template specializations. Those template specializations identical to some existing type. Conceptually I would like to implement them as aliases/typedefs.
The following example code should show what I want to do:
template<class T> class Common {
/// general implementation
};
class TypeZ;
template<> class Common<Type1> = TypeZ; // <<< how to do this?
template<> class Common<Type2> = TypeZ;
template<> class Common<Type3> = TypeZ;
Is the above possible in some way in C++ (or C++11)? It would be great if I didn't have to implement Common<...>
as a class that inherits TypeZ
- the actual code is more complex than shown above and inheriting TypeZ
is not a good idea there.
Assuming only certain specialisations of Common
are aliases of TypeZ
then you can do:
template<class T> class Common {
struct type {
/// general implementation
};
};
template<> class Common<Type1> { using type = TypeZ; };
template<> class Common<Type2> { using type = TypeZ; };
template<> class Common<Type3> { using type = TypeZ; };
template<class T> using common_t = typename Common<T>::type;
Then you use common_t<T>
rather than Common<T>
.
Just to entertain the inheritance idea, have you tried this?
template<> class Common<Type1> : public TypeZ { using TypeZ::TypeZ; };
template<> class Common<Type2> : public TypeZ { using TypeZ::TypeZ; };
template<> class Common<Type3> : public TypeZ { using TypeZ::TypeZ; };
Then you don't need to use a nested type alias.
Yes you can, by using type aliases:
template<typename T> using Common = TypeZ;
See the link for more examples of what is possible. using
can be used anywhere typedef
can be used, plus in template aliases like the above, so I recommend using using
over typedef
everywhere you write C++11.
If you need a more complicated mapping, you can use some simple template metaprogramming using std::enable_if
or std::conditional
combined with std::is_same
.
For example, if you need to specialize for 3 types only, use this:
#include <type_traits>
class Type1 {};
class Type2 {};
class Type3 {};
class Type4 {};
class TypeZ {};
// Implementation 1
template<typename T>
constexpr bool is_Type123_func()
{
return std::is_same<T, Type1>() || std::is_same<T, Type2>() || std::is_same<T, Type3>();
}
template<typename T>
using Common_byfunc = typename std::conditional<is_Type123_func<T>(), TypeZ, T>::type;
static_assert(std::is_same<Common_byfunc<Type1>, TypeZ>(), "");
static_assert(std::is_same<Common_byfunc<Type2>, TypeZ>(), "");
static_assert(std::is_same<Common_byfunc<Type3>, TypeZ>(), "");
static_assert(!std::is_same<Common_byfunc<Type4>, TypeZ>(), "");
// Implementation 2
template<typename T>
struct is_Type123 : public std::conditional<std::is_same<T, Type1>() || std::is_same<T, Type2>() || std::is_same<T, Type3>(), std::true_type, std::false_type>::type {};
template<typename T>
using Common = typename std::conditional<is_Type123<T>::value, TypeZ, T>::type;
static_assert(std::is_same<Common<Type1>, TypeZ>(), "");
static_assert(std::is_same<Common<Type2>, TypeZ>(), "");
static_assert(std::is_same<Common<Type3>, TypeZ>(), "");
static_assert(!std::is_same<Common<Type4>, TypeZ>(), "");
Both implementations are equivalent up to a name and the fact you have to use a function call operator ()
or the member accessor ::value
in the std::conditional
.
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