Is there a technique / best style to group class template specializations for certain types ?
An example : Lets say I have a class template Foo
and I need to have it specialized the same for the typeset
A = { Line, Ray }
and in another way for the typeset B
B = { Linestring, Curve }
What I'm doing so far : (the technique is also presented here for functions)
#include <iostream>
#include <type_traits>
using namespace std;
// 1st group
struct Line {};
struct Ray {};
// 2nd group
struct Curve {};
struct Linestring {};
template<typename T, typename Groupper=void>
struct Foo
{ enum { val = 0 }; };
// specialization for the 1st group
template<typename T>
struct Foo<T, typename enable_if<
is_same<T, Line>::value ||
is_same<T, Ray>::value
>::type>
{
enum { val = 1 };
};
// specialization for the 2nd group
template<typename T>
struct Foo<T, typename enable_if<
is_same<T, Curve>::value ||
is_same<T, Linestring>::value
>::type>
{
enum { val = 2 };
};
int main()
{
cout << Foo<Line>::val << endl;
cout << Foo<Curve>::val << endl;
return 0;
}
An extra helper struct enable_for
would shorten the code (and allow to write the accepted types directly). Any other suggestions, corrections? Shouldn't this involve less effort?
The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.
Template classes and functions can make use of another kind of template parameter known as a non-type parameter. A template non-type parameter is a template parameter where the type of the parameter is predefined and is substituted for a constexpr value passed in as an argument.
What is the syntax to use explicit class specialization? Explanation: The class specialization is creation of explicit specialization of a generic class. We have to use template<> constructor for this to work. It works in the same way as with explicit function specialization.
Class Template: We can define a template for a class. For example, a class template can be created for the array class that can accept the array of various types such as int array, float array or double array.
You can also do this with your own traits and without enable_if
:
// Traits
template <class T>
struct group_number : std::integral_constant<int, 0> {};
template <>
struct group_number<Line> : std::integral_constant<int, 1> {};
template <>
struct group_number<Ray> : std::integral_constant<int, 1> {};
template <>
struct group_number<Linestring> : std::integral_constant<int, 2> {};
template <>
struct group_number<Curve> : std::integral_constant<int, 2> {};
// Foo
template <class T, int Group = group_number<T>::value>
class Foo
{
//::: whatever
};
template <class T>
class Foo<T, 1>
{
//::: whatever for group 1
};
template <class T>
class Foo<T, 2>
{
//::: whatever for group 2
};
This has the advantage of automatically ensuring that each type is in at most one group.
Extra level of indirection by using two new type traits:
template<class T>
struct is_from_group1: std::false_type {};
template<>
struct is_from_group1<Line>: std::true_type {};
template<>
struct is_from_group1<Ray>: std::true_type {};
template<class T>
struct is_from_group2: std::false_type {};
template<>
struct is_from_group2<Curve>: std::true_type {};
template<>
struct is_from_group2<Linestring>: std::true_type {};
and then do the enable_if
on these type traits
// specialization for the 1st group
template<typename T>
struct Foo<T, typename enable_if<
is_from_group1<T>::value
>::type>
{
enum { val = 1 };
};
// specialization for the 2nd group
template<typename T>
struct Foo<T, typename enable_if<
is_from_group2<T>::value
>::type>
{
enum { val = 2 };
};
Note that you still need to make sure that no user-defined class is added to both groups, or you will get an ambiguity. You can either use @Angew's solution to derive from a numbered group using std::integral_constant<int, N>
for group number N
. Or, if these groups are not logically exclusive, you could add an extra condition inside the enable_if
that guards against this.
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