C++ Standard Templates (STL) – Type Support (type attributes, is_literal_type, is_polymorphic, is_empty)

Type attributes

A type attribute defines a compile-time template-based structure for querying or modifying the properties of a type.

Attempting to specialize a template defined in the header results in undefined behavior, except that std::common_type can be specialized as described.

Templates defined in the header file may be instantiated with incomplete types unless otherwise specified, although instantiating standard library templates with incomplete types is generally prohibited.

Type attribute

Defined in header file

Inherited from std::integral_constant

Member constants

value

[static]

If T is a literal type, it is true, otherwise it is false
(Public static member constants)
Member functions

operator bool

Convert the object to bool and return value
(Public member function)

operator()

(C++14)

Return value
(Public member function)
Member type
Type Definition
value_type bool
type std::integral_constant

Check whether the type is a literal type

std::is_literal_type

template< class T >
struct is_literal_type;

(since C++11)
(Deprecated in C++17)
(Removed in C++20)

Provides member constant value equal to true if T satisfies all literal type (LiteralType) requirements. For any other type, value is false .

The behavior is undefined if std::remove_all_extents_t is an incomplete type and is not (possibly cv-qualified) void.

Template parameters
T Type to check
Auxiliary variable template

template< class T >
inline constexpr bool is_literal_type_v = is_literal_type::value;

(since C++17)
(deprecated)
(Removed in C++20)
Attention

Only literal types can be used as parameters or return types of constexpr functions. Only literal classes can have constexpr member functions.

Call example
#include <iostream>
#include <string>
#include <type_traits>

struct A
{
    int m;
};

struct B
{
    virtual ~B();
};

int main()
{
    std::cout << std::boolalpha;
    std::cout << "std::is_literal_type<int>::value: "
              << std::is_literal_type<int>::value << std::endl;
    std::cout << "std::is_literal_type<double>::value: "
              << std::is_literal_type<double>::value << std::endl;
    std::cout << "std::is_literal_type<std::string>::value: "
              << std::is_literal_type<std::string>::value << std::endl;
    std::cout << "std::is_literal_type<A>::value: "
              << std::is_literal_type<A>::value << std::endl;
    std::cout << "std::is_literal_type<B>::value: "
              << std::is_literal_type<B>::value << std::endl;

    return 0;
}
Output

Checks whether the type is a class (but not a union) type and has no non-static data members

std::is_empty

template< class T >
struct is_empty;

(C++11 onwards)

If T is an empty class type (that is, no non-static data member with a 0-sized bitfield, no virtual functions, no virtual base classes, and no non-union class type that is not a non-empty base class), then Provides a member constant value that is equal to true. For any other type, value is false .

If T is a non-union type, then T should be a complete type; otherwise the behavior is undefined.

Template parameters
T Type to check
Auxiliary variable template

template< class T >
inline constexpr bool is_empty_v = is_empty::value;

(C++17 onwards)
Note

Because of the empty base class optimization, inheriting from an empty class type usually does not increase the size of the class.

std::is_empty and all other type attributes are empty classes.

Call example
#include <iostream>
#include <type_traits>
#include <string>

struct A {};

struct B
{
    int m;
};

struct C
{
    virtual ~C();
};

union D {};

struct E
{
    [[no_unique_address]] D d;
};

int main()
{
    std::cout << std::boolalpha;
    std::cout << "std::is_empty<int>::value: "
              << std::is_empty<int>::value << std::endl;
    std::cout << "std::is_empty<double>::value: "
              << std::is_empty<double>::value << std::endl;
    std::cout << "std::is_empty<std::string>::value: "
              << std::is_empty<std::string>::value << std::endl;
    std::cout << "std::is_empty<A>::value: "
              << std::is_empty<A>::value << std::endl;
    std::cout << "std::is_empty<B>::value: "
              << std::is_empty<B>::value << std::endl;
    std::cout << "std::is_empty<C>::value: "
              << std::is_empty<C>::value << std::endl;
    std::cout << "std::is_empty<D>::value: "
              << std::is_empty<D>::value << std::endl;
    std::cout << "std::is_empty<E>::value: "
              << std::is_empty<E>::value << std::endl; // The result depends on the ABI

    return 0;
}
Output

Check whether the type is a polymorphic class type

std::is_polymorphic

template< class T >
struct is_polymorphic;

(C++11 onwards)

If T is a polymorphic class (that is, a non-union class that declares or inherits at least one virtual function), provide the member constant value equal to true. For any other type, value is false .

If T is a non-union type, then T should be a complete type; otherwise the behavior is undefined.

Template parameters
T Type to check
Auxiliary variable template

template< class T >
inline constexpr bool is_polymorphic_v = is_polymorphic::value;

(C++17 onwards)
Possible implementation
namespace detail {
 
template <class T>
std::true_type detect_is_polymorphic(
decltype(dynamic_cast<const volatile void*>(static_cast<T*>(nullptr)))
);
template <class T>
std::false_type detect_is_polymorphic(...);
} // namespace detail
 
template <class T>
struct is_polymorphic:
decltype(detail::detect_is_polymorphic<T>(nullptr)) {};
Call example
#include <iostream>
#include <type_traits>

struct A
{
    int m;
};

struct B
{
    virtual void foo();
};

struct C : B {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << "std::is_polymorphic<int>::value: "
              << std::is_polymorphic<int>::value << std::endl;
    std::cout << "std::is_polymorphic<double>::value: "
              << std::is_polymorphic<double>::value << std::endl;
    std::cout << "std::is_polymorphic<std::string>::value: "
              << std::is_polymorphic<std::string>::value << std::endl;
    std::cout << "std::is_polymorphic<A>::value: "
              << std::is_polymorphic<A>::value << std::endl;
    std::cout << "std::is_polymorphic<B>::value: "
              << std::is_polymorphic<B>::value << std::endl;
    std::cout << "std::is_polymorphic<C>::value: "
              << std::is_polymorphic<C>::value << std::endl;

    return 0;
}
Output