C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Achieving pragma pack(1) with typedef<unaligned>

From: Sebastian Wittmeier <wittmeier_at_[hidden]>
Date: Mon, 8 Jun 2026 14:58:55 +0200
Much of it is possible with C++26. So no need for a language change or new syntax?     Sorry, I asked ChatGPT to create the code as a simple template, first the usage, then the underlying code:   #include <cstdint> #include <type_traits>     // our aligned struct struct Message {   std::uint16_t kind;   std::uint32_t length;   double value; };   // create an unaligned version   using UnalignedMessage = unaligned_struct_t<Message>;     // usage   int main() {   UnalignedMessage m{};   m.kind = std::uint16_t{7};   m.length = std::uint32_t{1024};   m.value = 3.5;   std::uint16_t kind = m.kind.load();   std::uint32_t len = m.length;   double value = m.value; }   // test sizes and types to prove that it works   static_assert(std::same_as<    decltype(UnalignedMessage::kind),   unaligned<std::uint16_t> >); static_assert(std::same_as<    decltype(UnalignedMessage::length),   unaligned<std::uint32_t> >); static_assert(std::same_as<   decltype(UnalignedMessage::value),   unaligned<double> >); static_assert(alignof(UnalignedMessage) == 1); static_assert(sizeof(UnalignedMessage) == sizeof(std::uint16_t) + sizeof(std::uint32_t) + sizeof(double));     // implementation   #include <cstddef> #include <cstring> #include <meta> #include <type_traits> #include <vector>     // make a single type unaligned -> std::unaligned<T>? template<class T> class unaligned {    using object_type = std::remove_cv_t<T>;   static_assert(std::is_object_v<T>);   static_assert(!std::is_reference_v<T>);   static_assert(!std::is_array_v<T>);   static_assert(!std::is_volatile_v<T>);   static_assert(std::is_trivially_copyable_v<object_type>);   std::byte bytes_[sizeof(object_type)]{}; public:   using value_type = T;   unaligned() = default;   explicit unaligned(T const& value) noexcept {     store(value);   }   auto load() const noexcept -> T {     object_type value;     std::memcpy(&value, bytes_, sizeof(value));     return value;   }   auto store(T const& value) noexcept -> void {     std::memcpy(bytes_, &value, sizeof(value));   }   auto operator=(T const& value) noexcept -> unaligned& {      store(value);     return *this;   }   operator T() const noexcept {     return load();   } }; static_assert(alignof(unaligned<int>) == 1); static_assert(sizeof(unaligned<int>) == sizeof(int));   namespace detail { consteval void validate_unaligned_source(std::meta::info source) {     using namespace std::meta;     constexpr auto ctx = access_context::unchecked();     if (!bases_of(source, ctx).empty()) {         throw "source type must not have base classes";     }     for (info member : members_of(source, ctx)) {         // Ignore implicitly declared special member functions.         if (is_function(member) && !is_user_declared(member)) {             continue;         }         if (!is_nonstatic_data_member(member)) {             throw "source type must declare only non-static data members";         }         if (!is_public(member)) {             throw "all source data members must be public";         }         if (!has_identifier(member)) {             throw "all source data members must have names";         }         if (is_bit_field(member)) {             throw "bit-fields are not supported";         }     } }   consteval auto make_unaligned_member_specs(std::meta::info source)     -> std::vector<std::meta::info> {     using namespace std::meta;     validate_unaligned_source(source);     constexpr auto ctx = access_context::unchecked();     std::vector<info> specs;     for (info member : nonstatic_data_members_of(source, ctx)) {         info member_type = type_of(member);         info wrapped_type = substitute(^^unaligned, {member_type});         specs.push_back(             data_member_spec(                 wrapped_type,                 {.name = identifier_of(member)}             )         );     }     return specs; } } // namespace detail template<class Source> struct unaligned_struct {     static_assert(std::is_class_v<Source>);     static_assert(std::is_aggregate_v<Source>);     struct type;     consteval {         std::meta::define_aggregate(             ^^type,             detail::make_unaligned_member_specs(^^Source)         );     } }; template<class Source> using unaligned_struct_t = typename unaligned_struct<Source>::type;     -----Ursprüngliche Nachricht----- Von:Alejandro Colomar via Std-Proposals <std-proposals_at_[hidden]> Gesendet:Mo 08.06.2026 14:50 Betreff:Re: [std-proposals] Achieving pragma pack(1) with typedef<unaligned> Anlage:signature.asc An:Frederick Virchanza Gotham via Std-Proposals <std-proposals_at_[hidden]>; CC:Alejandro Colomar <une+cxx_std-proposals_at_[hidden]>; Hi Frederick, On 2026-06-08T13:21:27+0100, Frederick Virchanza Gotham via Std-Proposals wrote: > On Mon, Jun 8, 2026 at 1:11 AM Alejandro Colomar wrote: > > > > Also, keeping a struct K that is not packed is going to be error prone. > > One might use struct J thinking it's also packed. > > > struct K_unpacked { . . .  }; > > typedef< std::unaligned > K_unpacked K; I still don't see why you'd want to keep a struct that you don't want. It might make more sense as typedef<std::unaligned> struct {...} K; But needing typedef to make a structure unaligned seems to be a workaround.  I'd rather make it a type specifier _Packed, or an unignorable attribute such as [[::packed]].  We also need this in C, FWIW. > > Have a lovely night! > > > It's a little after noon where I am. Have a lovely night when it arrives!  :) Alex -- <https://www.alejandro-colomar.es> -- Std-Proposals mailing list Std-Proposals_at_[hidden] https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2026-06-08 13:02:17