#include #if 0 set -xe g++ -std=c++17 -fsyntax-only compressed_pair.cc clang++ -std=c++17 -fsyntax-only compressed_pair.cc g++ -std=c++20 -fsyntax-only compressed_pair.cc clang++ -std=c++20 -fsyntax-only compressed_pair.cc exit 0 #endif #include // Minimal compressed pair implementation. // // In cpp even if a class is zero-sized, adding a member of such a class, // allocates 1 byte in the layout of the instantiating class. In generic // programming one sometimes wants to store a member of a template argument and // in the best case for zero-sized template types one does not want to pay a // price. // // One example for this is std::unique_ptr with a custom state-less deleter: // #include struct freer { void operator()(void* p) { std::free(p); } }; std::unique_ptr ptr{nullptr}; static_assert(sizeof(ptr) == sizeof(char*), ""); // // Before cpp20 this can be achieved with some template specialization tricks // and deriving from the type if it is not empty and not final. // // Starting with cpp20 the [[no_unique_address]] attribute [1] was added which // allows the compiler to not allocate space in the layout of a class for a // given member if that is zero-sized. // // [1] https://en.cppreference.com/w/cpp/language/attributes/no_unique_address namespace cpp11 { template && !std::is_final_v> struct entry { T& get() { return val; } T val; }; template struct entry : T { T& get() { return *static_cast(this); } }; template struct pair : entry, entry { T& first() { return static_cast*>(this)->get(); } U& second() { return static_cast*>(this)->get(); } }; } // namespace cpp11 struct empty {}; #if __cplusplus >= 202002L namespace cpp20 { template struct pair { T& first() { return m_first; } U& second() { return m_second; } [[no_unique_address]] T m_first; [[no_unique_address]] U m_second; }; } // namespace cpp20 #endif // -- TEST ME ------------------------------------------------------------------ static_assert(sizeof(cpp11::pair) == 8); static_assert(sizeof(cpp11::pair) == 4); static_assert(sizeof(cpp11::pair) == 2); #if __cplusplus >= 202002L static_assert(sizeof(cpp20::pair) == 8); static_assert(sizeof(cpp20::pair) == 4); static_assert(sizeof(cpp20::pair) == 2); #endif