Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::common_type trait for user defined types

Since C++11 the type trait std::common_type was introduced. std::common_type determines the common type between all of its template arguments. In C++14 its helper type std::common_type_t was also introduce in order to make code that uses std::common_type type trait shorter.

std::common_type is particular useful in overloaded arithmetic operators, e.g.,

template<typename T1, typename T2>
std::common_type_t<T1, T2> operator+(T1 const &t1, T2 const &t2) {
  return t1 + t2;
}

It works fine if its templates arguments are built in types (e.g., int, double). However I doesn't seem to work if I provide as template arguments to it user defined types e.g.,

struct A {};
struct B {};

std::common_type_t<A, B> // doesn't work

Q: How I can make std::common_type trait work with user defined types?

like image 564
101010 Avatar asked Apr 09 '16 21:04

101010


1 Answers

According to the draft standard N4582 §20.13.2 Header synopsis [meta.type.synop] (Emphasis Mine):

The behavior of a program that adds specializations for any of the templates defined in this subclause is undefined unless otherwise specified.

Consequently, adding specializations for type_traits can cause undefined behaviour unless somewhere else in the standard there's a wording for a specific type trait that supersedes the wording displayed above. Fortunately, in Table 60 - Other transformations:

enter image description here

There's the wording:

A program may specialize this trait if at least one template parameter in the specialization is a user-defined type. [ Note: Such specializations are needed when only explicit conversions are desired among the template arguments. — end note ]

This means that specializations of std::common_type type trait that have at least one user-defined type are perfectly allowed. In fact if you take a look at §20.15.4.3 Specializations of common_type [time.traits.specializations] you'll find out that STL already defines specializations of std::common_type for user defined types std::chrono::duration and std::chrono::time_point.

Thus, the correct way to make common_type "work" for user defined types is to provide a specialization of it for those specific types, e.g.,

struct A {};
struct B {};

namespace std {
  template<>
  struct common_type<A, B> {
    using type = A;
  };
} 

In the code example above we specify that the common type between A and B is A.

like image 92
101010 Avatar answered Oct 06 '22 00:10

101010