std::is_aggregate(3)

πŸ“¦
version 2024.07.05 Β· 3 versions
, in nixpkgs unstable, opensuse-leap 16.0

πŸ’– NAME πŸ’–

okay so bestie, this is std::is_aggregate β€” the whole NAME section is literally std::is_aggregate - std::is_aggregate, and that's iconic. We're in the C++ Standard Libary manual, page std::is_aggregate(3), and yes I'm obsessed. It's giving "we check if a type is an aggregate" energy. periodt. πŸ’…

✨ Synopsis ✨

Defined in header <type_traits> β€” exact, don't forget it:

Defined in header <type_traits>
template< class T >              (since C++17)
struct is_aggregate;

std::is_aggregate is a UnaryTypeTrait. No cap.

If T is an aggregate type, it provides the member constant value equal true. For any other type, value is false. Slay.

⚠️ if T is an incomplete type other than an array type or (possibly cv-qualified) void, the behavior is undefined. That's UB, bestie β€” not the cute kind. 😭
🚨 if the program adds specializations for std::is_aggregate or std::is_aggregate_v, the behavior is undefined. Do not do that. Not today. Not ever. πŸ’€

🌸 Template parameters 🌸

  • T β€” a type to check. That's the whole job, lowkey.

πŸŽ€ Helper variable template πŸŽ€

template< class T >
(since C++17)
inline constexpr bool is_aggregate_v = is_aggregate<T>::value;

πŸ’« Inherited from std::integral_constant πŸ’«

🌈 Member constants 🌈

  • value β€” true if T is an aggregate 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 πŸ“

  • value_type β€” bool
  • type β€” std::integral_constant<bool, value>

πŸ’… Notes πŸ’…

Feature-test macro situation, iykyk:

  • Feature-test macro: __cpp_lib_is_aggregate β€” Value: 201703L β€” Std: (C++17) β€” Feature: std::is_agregate

πŸ”₯ Example πŸ”₯

// Run this code β€” go off, bestie:

#include <new>
#include <type_traits>
#include <utility>

// constructs a T at the uninitialized memory pointed to by p using
// list-initialization for aggregates and non-list initialization otherwise
template<class T, class... Args>
T* construct(T* p, Args&&... args)
{
    if constexpr (std::is_aggregate_v<T>)
        return ::new (static_cast<void*>(p)) T{std::forward<Args>(args)...};
    else
        return ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
}

struct A { int x, y; };
struct B { B(int, const char*) {} };

int main()
{
    std::aligned_union_t<1, A, B> storage;
    [[maybe_unused]] A* a = construct(reinterpret_cast<A*>(&storage), 1, 2);
    [[maybe_unused]] B* b = construct(reinterpret_cast<B*>(&storage), 1, "hello");
}

πŸ’€ Defect reports πŸ’€

The following behavior-changing defect reports were applied retroactively to previously published C++ standards. History lesson, but make it fashion. ✨

  • DR LWG 3823, applied to C++17 β€” Behavior as published: "The behavior is undefined if T is an array type but std::remove_all_extents_t<T> is an incomplete type." Correct behavior: "The behavior is defined regardless of the incompleteness of std::remove_all_extents_t<T> as long as T is an array type."

okay bye bestie 🫢 this came from source http://cppreference.com, version/date 2024.06.10, and it's the std::is_aggregate(3) page signing off. mwah πŸ’‹πŸŽ€

πŸ“¦ where this page comes from