I am specializing std::common_type
for my type. I defined the following specialization:
common_type<my_type, my_type>
And all is well. Then someone comes along and calls std::common_type<my_type, my_type &>
. The default version acts the same if you pass a reference vs. not a reference (as it calls std::decay
on the types). However, it doesn't defer to the non-reference version of std::common_type
, which I would need to work correctly. Is there a better way than having to do something like this (leaving out rvalue-reference to const for simplicity):
common_type<my_type, my_type>
common_type<my_type, my_type &>
common_type<my_type, my_type const &>
common_type<my_type, my_type volatile &>
common_type<my_type, my_type const volatile &>
common_type<my_type, my_type &&>
common_type<my_type, my_type volatile &&>
common_type<my_type &, my_type>
common_type<my_type const &, my_type>
common_type<my_type volatile &, my_type>
common_type<my_type const volatile &, my_type>
common_type<my_type &&, my_type>
common_type<my_type volatile &&, my_type>
common_type<my_type &, my_type &>
common_type<my_type &, my_type const &>
common_type<my_type &, my_type volatile &>
...
Surely there is a better way? By my count, that is 49 possible versions if we ignore const &&
and const volatile &&
Note: my_type is actually a class template itself, so the specialize actually looks more like
template<intmax_t lhs_min, intmax_t lhs_max, intmax_t rhs_min, intmax_t rhs_max>
class common_type<my_type<lhs_min, lhs_max>, my_type<rhs_min, rhs_max>>
Where the result is my_type<min(lhs_min, rhs_min), max(lhs_max, rhs_max)>
The solution would be fairly straightforward if I had full control over the primary template definitions, but I obviously cannot change std::common_type
.
It is possible in C++ to get a special behavior for a particular data type. This is called template specialization. Template allows us to define generic classes and generic functions and thus provide support for generic programming.
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.
How many types of specialization are there in c++? Explanation: There are two types of specialization. They are full specialization and partial specialization.
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.
As far as I know, you don't need to completely specialize both sides of the binary common_type
. This allows reducing the amount of specializations to 12 for one side. If you only need a common type between specializations of my_type
and my_type
, than it's sufficient to specialize on one side. Otherwise, you'd had to clone them on the right side, yielding 24 specializations.
struct my_type;
struct unique_t;
#include <type_traits>
template<class L, class R, class = void>
struct mytype_common_type
{
// not many specializations are required here,
// as you can use std::decay and don't have to use "Exact Matches"
using type = unique_t;
};
namespace std
{
template<class T> struct common_type<my_type, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type volatile, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const volatile, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type volatile&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const volatile&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type&&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const&&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type volatile&&, T>
: mytype_common_type<my_type, T> {};
template<class T> struct common_type<my_type const volatile&&, T>
: mytype_common_type<my_type, T> {};
}
template<class T>
using Decay = typename std::decay<T>::type;
int main()
{
static_assert(std::is_same<unique_t,
std::common_type<my_type const volatile&&, int>::type
>{}, "!");
}
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