std::is_scalar(3)

NAME
std::is_scalar - std::is_scalar

Synopsis
   Defined in header <type_traits>
   template< class T > (since C++11)
   struct is_scalar;
   std::is_scalar is a UnaryTypeTrait.
   If T is a scalar type, provides the member constant value equal true. For any other
   type, value is false.
   If the program adds specializations for std::is_scalar or std::is_scalar_v, the
   behavior is undefined.

Template parameters
   T - a type to check
   Helper variable template
   template< class T > (since C++17)
   inline constexpr bool is_scalar_v = is_scalar<T>::value; Inherited from std::integral_constant

Member constants
   value true if T is a scalar type, false otherwise
   [static] (public static member constant)

Member functions
   operator bool converts the object to bool, returns value
                 (public member function)
   operator() returns value
   (C++14) (public member function)

Member types
   Type Definition
   value_type bool
   type std::integral_constant<bool, value>

Notes
   Each individual memory location in the C++ memory model, including the hidden memory
   locations used by language features (e.g. virtual table pointer), has scalar type
   (or is a sequence of adjacent bit-fields of non-zero length). Sequencing of
   side-effects in expression evaluation, inter-thread synchronization, and dependency
   ordering are all defined in terms of individual scalar objects.

Possible implementation
   template<class T>
   struct is_scalar : std::integral_constant<bool, std::is_arithmetic<T>::value
                        || std::is_enum<T>::value
                        || std::is_pointer<T>::value
                        || std::is_member_pointer<T>::value
                        || std::is_null_pointer<T>::value>
   {};

Example
// Run this code
 #include <iostream>
 #include <type_traits>
 #include <typeinfo>
 #include <utility>
 template<typename Head, typename... Tail>
 void are_scalars(Head&& head, Tail&&... tail)
 {
     using T = std::decay_t<decltype(head)>;
     std::cout << typeid(T).name() << " is "
               << (std::is_scalar_v<T> ? "" : "not ")
               << "a scalar\n";
     if constexpr (sizeof... (Tail))
     {
         are_scalars(std::forward<decltype(tail)>(tail)...);
     }
 }
 int main()
 {
     struct S { int m; } s;
     int S::* mp = &S::m;
     enum class E { e };
     are_scalars(42, 3.14, E::e, "str", mp, nullptr, s);
 }

Possible output:
 int is a scalar
 double is a scalar
 main::E is a scalar
 char const* is a scalar
 int main::S::* is a scalar
 nullptr is a scalar
 main::S is not a scalar

See also
   is_arithmetic checks if a type is an arithmetic type
   (C++11) (class template)
   is_enum checks if a type is an enumeration type
   (C++11) (class template)
   is_pointer checks if a type is a pointer type
   (C++11) (class template)
   is_member_pointer checks if a type is a pointer to a non-static member function or
   (C++11) object
                     (class template)