C++ Standard Templates (STL) – Type Support (type attributes, is_abstract, is_signed, is_unsigned)

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

Inherited from std::integral_constant

Member constants

value

[static]

If T is an abstract class 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 an abstract class type

std::is_abstract

template< class T >
struct is_abstract;

(C++11 onwards)

If T is an abstract class (that is, a non-union class type that declares or inherits at least one pure virtual function), provide a member constant value equal to true. For other types, 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_abstract_v = is_abstract::value;

(C++17 onwards)
Call example
#include <iostream>
#include <type_traits>

struct A
{
    int m;
};

struct B
{
    virtual void foo();
};

struct C
{
    virtual void foo() = 0;
};

struct D : C {};

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

    return 0;
}
Output

Check whether the type is a signed arithmetic type

std::is_signed

template< class T >
struct is_signed;

(C++11 onwards)

If T is an arithmetic type and T(-1) < T(0), provide a member constant value equal to true: this is true for floats Yields true for dot types and signed integer types, and false for unsigned integer types and bool types.

For any other type, value is false .

Template parameters
T - Type to check
Auxiliary variable template

template< class T >
inline constexpr bool is_signed_v = is_signed::value;

(C++17 onwards)
Possible implementation
namespace detail {
template<typename T,bool = std::is_arithmetic<T>::value>
struct is_signed : std::integral_constant<bool, T(-1) < T(0)> {};
 
template<typename T>
struct is_signed<T,false> : std::false_type {};
} // namespace detail
 
template<typename T>
struct is_signed : detail::is_signed<T>::type {};
Call example
#include <iostream>
#include <type_traits>

class A {};
enum B : int {};
enum class C : int {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << "std::is_signed<A>::value: "
              << std::is_signed<A>::value << std::endl;
    std::cout << "std::is_signed<std::string>::value: "
              << std::is_signed<std::string>::value << std::endl;
    std::cout << "std::is_signed<float>::value: "
              << std::is_signed<float>::value << std::endl;
    std::cout << "std::is_signed<signed int>::value: "
              << std::is_signed<signed int>::value << std::endl;
    std::cout << "std::is_signed<unsigned int>::value: "
              << std::is_signed<unsigned int>::value << std::endl;
    std::cout << "std::is_signed<B>::value: "
              << std::is_signed<B>::value << std::endl;
    std::cout << "std::is_signed<C>::value: "
              << std::is_signed<C>::value << std::endl;

    // Short form:
    std::cout << "std::is_signed<signed int>(): "
              << std::is_signed<signed int>() << std::endl;
    std::cout << "std::is_signed<unsigned int>(): "
              << std::is_signed<unsigned int>() << std::endl;

    return 0;
}
Output

Check whether the type is an unsigned arithmetic type

std::is_unsigned

template< class T >
struct is_unsigned;

(C++11 onwards)

If T is an arithmetic type and T(0) < T(-1), then provide a member constant value equal to true: this has no Yields true for signed integer types and bool types, and false for signed integer and floating-point types.

For any other type, value is false .

Template parameters
T - Type to check
Auxiliary variable template

template< class T >
inline constexpr bool is_unsigned_v = is_unsigned::value;

(C++17 onwards)
Possible implementation
namespace detail {
template<typename T,bool = std::is_arithmetic<T>::value>
struct is_unsigned : std::integral_constant<bool, T(0) < T(-1)> {};
 
template<typename T>
struct is_unsigned<T,false> : std::false_type {};
} // namespace detail
 
template<typename T>
struct is_unsigned : detail::is_unsigned<T>::type {};
Call example
#include <iostream>
#include <type_traits>

class A {};
enum B : int {};
enum class C : int {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << "std::is_unsigned<A>::value: "
              << std::is_unsigned<A>::value << std::endl;
    std::cout << "std::is_unsigned<std::string>::value: "
              << std::is_unsigned<std::string>::value << std::endl;
    std::cout << "std::is_unsigned<float>::value: "
              << std::is_unsigned<float>::value << std::endl;
    std::cout << "std::is_unsigned<signed int>::value: "
              << std::is_unsigned<signed int>::value << std::endl;
    std::cout << "std::is_unsigned<unsigned int>::value: "
              << std::is_unsigned<unsigned int>::value << std::endl;
    std::cout << "std::is_unsigned<B>::value: "
              << std::is_unsigned<B>::value << std::endl;
    std::cout << "std::is_unsigned<C>::value: "
              << std::is_unsigned<C>::value << std::endl;

    // Short form:
    std::cout << "std::is_unsigned<signed int>(): "
              << std::is_unsigned<signed int>() << std::endl;
    std::cout << "std::is_unsigned<unsigned int>(): "
              << std::is_unsigned<unsigned int>() << std::endl;

    return 0;
}
Output