M
In C++11 type_traitsThere's a class pattern is_base_of:template< class Base, class Derived >
struct is_base_of;
There's a static stable member in this class, bool by name value♪ It's installed true if Derived is a manufactured type from Base(whispering, be it) public♪ protected or private inheritance. And false otherwise. It should also be noted that value installed trueif Base and Derived are the same type (not working for fundamental types and indicators).This is the example of the code:#include <iostream>
#include <type_traits>
using namespace std;
class A {};
class B : public A {};
class C : protected A {};
class D : private A {};
class F : public D {};
class Z {};
int main()
{
cout << boolalpha;
cout << is_base_of<A, B>::value << endl;
cout << is_base_of<A, C>::value << endl;
cout << is_base_of<A, D>::value << endl;
cout << is_base_of<A, A>::value << endl;
cout << is_base_of<A, F>::value << endl;
cout << is_base_of<A, Z>::value << endl;
return 0;
}
And we'll get:true
true
true
true
true
false
In C++17, auxiliary variable template emerged:template< class Base, class Derived >
inline constexpr bool is_base_of_v = is_base_of<Base, Derived>::value;
It helps avoid resorting to a member value♪ It means that:cout << is_base_of_v<A, B> << endl;
cout << is_base_of_v<A, C> << endl;
cout << is_base_of_v<A, D> << endl;
cout << is_base_of_v<A, A> << endl;
cout << is_base_of_v<A, F> << endl;
cout << is_base_of_v<A, Z> << endl;
And we'll get the same conclusion as before.Further details can be found here: https://en.cppreference.com/w/cpp/types/is_base_of In C++11 type_traitsThere's a class pattern is_convertible:template< class From, class To >
struct is_convertible;
He's checking if a guy can. From be converted into a type To♪ In this class, as in is_base_of, there's a static stable member. value type bool♪ It's installed trueif type From may not be clearly converted into a type Toand false otherwise.Example of code:#include <iostream>
#include <type_traits>
using namespace std;
class A {};
class B : public A {};
class C : protected A {};
class D : private A {};
class X
{
public:
operator A() { return a; }
private:
A a;
};
class Y
{
public:
explicit operator A() { return a; }
private:
A a;
};
int main()
{
cout << boolalpha;
cout << is_convertible<A*, B*>::value << endl;
cout << is_convertible<B*, A*>::value << endl;
cout << is_convertible<C*, A*>::value << endl;
cout << is_convertible<D*, A*>::value << endl;
cout << is_convertible<X, A>::value << endl;
cout << is_convertible<Y, A>::value << endl;
return 0;
}
And conclusion:false
true
false
false
true
false
No explanation.is_convertible<A*, B*>::value Yeah. false, because a non-exhaustive transformation is prohibited in C+++.is_convertible<B*, A*>::value Yeah. truebecause the non-remarkable conversion is permitted only for open inheritance. For this reason is_convertible<C*, A*>::value and is_convertible<D*, A*>::value - Yes. false♪is_convertible<X, A>::value Yeah. true'Cause it's cool. X has a transformer Awhich may be summoned. He's not declared like explicit♪is_convertible<Y, A>::value Yeah. false'Cause his transformation operator is A Declared as explicitand it can't be caused by the invisible.In C++17, auxiliary variable template emerged:template< class From, class To >
inline constexpr bool is_convertible_v = is_convertible<From, To>::value;
It helps avoid resorting to a member value♪ It means that:cout << is_convertible_v<A*, B*> << endl;
cout << is_convertible_v<B*, A*> << endl;
cout << is_convertible_v<C*, A*> << endl;
cout << is_convertible_v<D*, A*> << endl;
cout << is_convertible_v<X, A> << endl;
cout << is_convertible_v<Y, A> << endl;
We'll get the same conclusion as before.In more detail here: https://en.cppreference.com/w/cpp/types/is_convertible C++20 should have a convenience derived_from in file concepts:template< class Derived, class Base >
concept derived_from =
std::is_base_of_v<Base, Derived> &&
std::is_convertible_v<const volatile Derived*, const volatile Base*>;
In more detail here: https://en.cppreference.com/w/cpp/concepts/derived_from