C++ Standard Templates (STL) – Type support (type attributes, is_union, is_class, is_function)

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

Basic type categories

Inherited from std::integral_constant

Member constants

value

[static]

True if T is a union type, false otherwise
(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 union type

std::is_union

template< class T >
struct is_union;

(C++11 onwards)

Checks whether T is a union type. If T is a union type, provide the member constant value equal to true. Otherwise value , equal to false .

Template parameters
T Type to check
Auxiliary variable template

template< class T >
inline constexpr bool is_union_v = is_union::value;

(C++17 onwards)

Check whether the type is not a union type

std::is_class

template< class T >
struct is_class;

(C++11 onwards)

Checks whether T is a non-union class type. If T is a class type (but not a union), provide a member constant value equal to true. Otherwise, value is equal to false .

Note that the type declared with the struct keyword is a class, so this attribute is true for “structure”.

Template parameters
T Type to check
Auxiliary variable template

template< class T >
inline constexpr bool is_class_v = is_class::value;

Possible implementation
namespace detail {
    template <class T> char test(int T::*);
    struct two { char c[2]; };
    template <class T> two test(...);
}
 
template <class T>
struct is_class : std::integral_constant<bool, sizeof(detail::test<T>(0))==1
                                             & amp; & amp; !std::is_union<T>::value> {};

Check whether it is a function type

std::is_function

template< class T >
struct is_function;

(C++11 onwards)

Checks whether T is a function type. For example, std::function, lambda, classes with overloaded operator() and pointers to functions are not function types. If T is a function type, provide member constant value equal to true. Otherwise, value is equal to false .

Template parameters
T Type to check
Auxiliary variable template

template< class T >
inline constexpr bool is_function_v = is_function::value;

(C++17 onwards)
Possible implementation
//Elementary template
template<class>
struct is_function : std::false_type { };
 
//Specialization of regular functions
template<class Ret, class... Args>
struct is_function<Ret(Args...)> : std::true_type {};
 
// Specializations for variadic functions such as std::printf
template<class Ret, class... Args>
struct is_function<Ret(Args......)> : std::true_type {};
 
// Specialization for function types with cv qualifier
template<class Ret, class... Args>
struct is_function<Ret(Args...) const> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile> : std::true_type {};
 
//Specialization of function types with reference qualifiers
template<class Ret, class... Args>
struct is_function<Ret(Args...) & amp;> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const & amp;> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile & amp;> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile & amp;> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) & amp;> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const & amp;> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile & amp;> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile & amp;> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) & amp; & amp;> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const & amp; & amp;> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile & amp; & amp;> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile & amp; & amp;> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) & amp; & amp;> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const & amp; & amp;> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) volatile & amp; & amp;> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile & amp; & amp;> : std::true_type {};
 
// Specializations for all noexcept versions above (C++ 17 and later)
 
template<class Ret, class... Args>
struct is_function<Ret(Args...) noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) & amp; noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const & amp; noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile & amp; noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile & amp; noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) & amp; noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const & amp; noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile & amp; noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile & amp; noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) & amp; & amp; noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const & amp; & amp; noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile & amp; & amp; noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) const volatile & amp; & amp; noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) & amp; & amp; noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const & amp; & amp; noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args...) volatile & amp; & amp; noexcept> : std::true_type {};
template<class Ret, class... Args>
struct is_function<Ret(Args......) const volatile & amp; & amp; noexcept> : std::true_type {};

Call example

#include <iostream>
#include <type_traits>

struct A {};

typedef union
{
    int a;
    float b;
} B;

struct C
{
    B d;
};

enum E {};

enum class Ec : int {};

struct D
{
    int fun() const &;
};

template<typename>
struct PM_traits {};

template<class T, class U>
struct PM_traits<U T::*>
{
    using member_type = U;
};

int f();

int main()
{
    std::cout << std::boolalpha;
    std::cout << "std::is_union<A>::value: "
              << std::is_union<A>::value << std::endl;
    std::cout << "std::is_union<B>::value: "
              << std::is_union<B>::value << std::endl;
    std::cout << "std::is_union<C>::value: "
              << std::is_union<C>::value << std::endl;
    std::cout << "std::is_union<int>::value: "
              << std::is_union<int>::value << std::endl;
    std::cout << "std::is_union<float>::value: "
              << std::is_union<float>::value << std::endl;
    std::cout << std::endl;

    std::cout << "std::is_class<A>::value: "
              << std::is_class<A>::value << std::endl;
    std::cout << "std::is_class<B>::value: "
              << std::is_class<B>::value << std::endl;
    std::cout << "std::is_class<C>::value: "
              << std::is_class<C>::value << std::endl;
    std::cout << "std::is_class<int>::value: "
              << std::is_class<int>::value << std::endl;
    std::cout << "std::is_class<float>::value: "
              << std::is_class<float>::value << std::endl;
    std::cout << std::endl;

    std::cout << "std::is_function<A>::value: "
              << std::is_function<A>::value << std::endl;
    std::cout << "std::is_function<int(int)>::value: "
              << std::is_function<int(int)>::value << std::endl;
    std::cout << "std::is_function<decltype(f)>::value: "
              << std::is_function<decltype(f)>::value << std::endl;
    std::cout << "std::is_function<int>::value: "
              << std::is_function<int>::value << std::endl;

    using T = PM_traits<decltype( & amp;D::fun)>::member_type; // T is int() const & amp;
    std::cout << "std::is_function<T>::value: "
              << std::is_function<T>::value << std::endl;
    std::cout << std::endl;

    return 0;
}
Output