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@lists.isocpp.org>
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@lists.isocpp.org>;
CC: Alejandro Colomar <une+cxx_std-proposals@alejandro-colomar.es>;
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@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals