C++17stladvanced
std::has_unique_object_representations
C++17 · Practical Modern · Compiler flag: -std=c++17
Explanation
A type trait that checks whether a type's value representation uses all of its object representation bits (no padding). Types satisfying this can be safely compared byte-by-byte using `memcmp` and hashed with `memcpy`-based hash functions.
Real-World Scenario
Enable a fast byte-level hash for types that are guaranteed to have no padding, in a high-performance hash map.
Quick Snippet
snippet.cpp
#include <type_traits>
struct Packed { int x; int y; };
struct Padded { char a; int b; }; // likely has padding
static_assert(std::has_unique_object_representations_v<int>);
// Padded may or may not satisfy this -- implementation-definedFull Example
has_unique_object_representations.cpp
// CodeNebula - C++17 Example: std::has_unique_object_representations
// Compile: g++ -std=c++17 -Wall -Wextra -o example has_unique_object_representations.cpp
// Demonstrates std::has_unique_object_representations, a type trait that
// checks whether two objects with the same value always have identical
// byte representations. This is crucial for types used with hashing
// (memcmp-based equality) or serialization via raw memory.
#include <iostream>
#include <type_traits>
#include <cstdint>
// Packed struct: no padding, unique representation
struct Packed {
uint32_t a;
uint32_t b;
};
// Struct with likely padding: NOT unique representation
struct Padded {
char c; // 1 byte
// padding // 3 bytes (typically)
int32_t i; // 4 bytes
};
// Struct with bool: may have non-unique bits
struct WithBool {
bool flag;
int value;
};
// Empty struct
struct Empty {};
// Bitfield struct: padding bits possible
struct Bitfield {
unsigned int x : 3;
unsigned int y : 5;
};
int main()
{
// ------------------------------------------------------------------
// 1. Fundamental types
// ------------------------------------------------------------------
std::cout << "=== Fundamental Types ===" << std::endl;
std::cout << " char : "
<< std::has_unique_object_representations_v<char> << std::endl;
std::cout << " int : "
<< std::has_unique_object_representations_v<int> << std::endl;
std::cout << " unsigned : "
<< std::has_unique_object_representations_v<unsigned> << std::endl;
std::cout << " uint8_t : "
<< std::has_unique_object_representations_v<uint8_t> << std::endl;
std::cout << " uint32_t : "
<< std::has_unique_object_representations_v<uint32_t> << std::endl;
// Float/double do NOT have unique representations (NaN, -0 vs +0)
std::cout << " float : "
<< std::has_unique_object_representations_v<float> << std::endl;
std::cout << " double : "
<< std::has_unique_object_representations_v<double> << std::endl;
// ------------------------------------------------------------------
// 2. User-defined types
// ------------------------------------------------------------------
std::cout << "\n=== User-Defined Types ===" << std::endl;
std::cout << " Packed : "
<< std::has_unique_object_representations_v<Packed> << std::endl;
std::cout << " Padded : "
<< std::has_unique_object_representations_v<Padded> << std::endl;
std::cout << "\n sizeof(Padded) = " << sizeof(Padded)
<< " (char=1 + pad + int=4)" << std::endl;
std::cout << " sizeof(Packed) = " << sizeof(Packed)
<< " (two uint32_t, no pad)" << std::endl;
// ------------------------------------------------------------------
// 3. Practical: safe hashing guard
// ------------------------------------------------------------------
std::cout << "\n=== Hashing Safety Check ===" << std::endl;
auto check_hashable = [](const char* name, bool unique) {
if (unique)
std::cout << " " << name << ": safe for memcmp-based hashing" << std::endl;
else
std::cout << " " << name << ": NOT safe for memcmp-based hashing" << std::endl;
};
check_hashable("Packed", std::has_unique_object_representations_v<Packed>);
check_hashable("Padded", std::has_unique_object_representations_v<Padded>);
check_hashable("int", std::has_unique_object_representations_v<int>);
check_hashable("double", std::has_unique_object_representations_v<double>);
return 0;
}
/*
Expected output (typical x86-64):
=== Fundamental Types ===
char : 1
int : 1
unsigned : 1
uint8_t : 1
uint32_t : 1
float : 0
double : 0
=== User-Defined Types ===
Packed : 1
Padded : 0
sizeof(Padded) = 8 (char=1 + pad + int=4)
sizeof(Packed) = 8 (two uint32_t, no pad)
=== Hashing Safety Check ===
Packed: safe for memcmp-based hashing
Padded: NOT safe for memcmp-based hashing
int: safe for memcmp-based hashing
double: NOT safe for memcmp-based hashing
*/
Run command
g++ -std=c++17 -Wall -Wextra -o example has_unique_object_representations.cpp