Re-implementation of `std::tuple` for MCUs
Good stuff!
improvements:
Your constructors should move the value.
constexpr pack(type arg) : value(arg) {}

vs
constexpr pack(type arg) : value(std::move(arg)) {}

Inconsistent constructor parameter:
Your pack&lt;...&gt; template's constructor's first argument is by reference, whereas your root template takes it by value. Be consistent, pick one. (the one by value with a move is the correct choice here)
This is not actually forwarding:
constexpr pack(const type&amp; arg, types&amp;&amp;... args)
          : value(arg), next(std::forward&lt;types&gt;(args)...) {}

Forwarding is needed when the template deduction can deduce the type of a parameter to be a reference. I.E. the arguments themselves need to be templated. That's not the case here.
You can simply use:
constexpr pack(type arg, types... args)
          : value(std::move(arg)), next(std::move(args)...) {}

Note that your make_tuple() function DOES perform forwarding, so that one is fine.
Get by reference, please.
Your get function returns by value, when a reference would make more sense:
auto get(const tuple&lt;types...&gt;&amp; tuple) {}

vs
const auto&amp; get(const tuple&lt;types...&gt;&amp; tuple) {}
auto&amp; get(tuple&lt;types...&gt;&amp; tuple) {}

make_tuple() should decay the type of its arguments.
Specifically, you should apply std::decay on a per-arg basis so that make_tuple(int&amp;, const float&amp;) returns a tuple&lt;int, float&gt;.
No EBO
Since you seem to care about packing, you should really be performing empty base class optimisation to get the maximum oomph out of your tuple class. This does make the code a lot more complicated though, so if you know for a fact that you'll never pack 0-sized types in a tuple, then I wouldn't bother.
A note on PACKED_TUPLES:
Making this a compile-time switch like this is pretty dicey, as you can eventually run into some nasty binary incompatibilities in the future. I would rather make a complete separate class called packed_tuple&lt;&gt;, and use the compile-time switch in higher-level code so that symbols related to tuple&lt;&gt; and packed_tuple&lt;&gt; remain consistent between binaries. It also allows you to mix packed and unpacked tuples in the same binary which is potentially convenient, since __attribute__((__packed__)) can have a substantial hit on performance.