Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is std::is_base_of<T, T> true when T is a class type, but false when T is a built-in type?

Per [meta.rel] (20.10.6 in C++14), for a class type T, std::is_base_of<T,T> is true, but for a built-in type T, std::is_base_of<T,T> is false. Colloquially speaking, class types are bases of themselves, but built-in types are not. What is the motivation/utility for this difference in treatment?

like image 538
KnowItAllWannabe Avatar asked Feb 23 '15 01:02

KnowItAllWannabe


1 Answers

The rationale goes back quite a ways, and is not well documented.

is_base_of was originally called is_base_and_derived, and was introduced in TR1. Dave Abrahams introduced an issue against this class in N1541, number 3.13:

Currently, is_base_and_derived<X,Y> returns false when X and Y are the same. This is technically correct (X isn’t its own base class), but it isn’t useful. The definition should be loosened to return true when X and Y are the same, even when the type isn’t actually a class.

Unfortunately the issue does not expound on why that definition is not useful. However the viewpoint was not unique at the time (2003). Andrei Alexandrescu's Modern C++ Design published two years earlier had much the same trait, and much the same comment in section 2.7 about its macro SUPERSUBCLASS, though this book also added a workaround macro if you really didn't want a class to be considered its own base.

Modern C++ Design goes on to use SUPERSUBCLASS in section 3.12 to order a Typelist in order of inheritance. Deep in the details of this exercise, the fact that SUPERSUBCLASS(T, T) is true is taken advantage of (for convenience in the implementation).

By 2004, the TR1 report, N1647, had adopted the notion that std::is_base_of<T,T>::value == true was useful when T is a non-union class type.

N2255 further clarifies how is_base_of is supposed to work for non-class types, and this change resulted in the wording that you see today. However there are extensive editorial differences between what this accepted paper proposes, and what was produced in the following draft (N2284). My opinion is that the editor greatly improved the wording.

The undocumented rationale for why N2255 created a division between non-union class types and everything else is that is_base_of historically answered questions about the inheritance hierarchy of types, with only a convenient "trick" that a class can be considered its own base via the "is-a" analysis. However types that can't possibly participate in an inheritance relationship should never qualify as base classes, according to the multiple authors of this trait.

Whether or not that was the best design is up for debate. However there are sufficient traits (e.g. is_class and is_same) to build whatever you need from these fundamental traits.

This is more of a history, rather than a straight-forward "why". However the point of this answer is to call out that is_base_of evolved over a great deal of time, through many iterations. And each iteration was felt at the time to be an evolutionary improvement upon what was there before.

And it all boils down to: This is the spec that the committee thought would be most useful. But as the spec & design evolved over many years, and through several authors, there exists no good overall design document or rationale.

like image 143
Howard Hinnant Avatar answered Oct 07 '22 01:10

Howard Hinnant