Reference:
Reducing C++ template bloat by factoring out the type-dependent portions of the function
COMDAT folding (also known as Identical Code Folding or ICF/Safe ICF) is a link-time optimization where the linker detects functions or read-only data sections that compile into byte-for-byte identical machine code, merges them into a single instance, and points all call sites to that unified copy.
When instantiates templates over types that share the same underlying memory layout and operations, the compiler often emits redundant assembly:
template <typename T>
void push_item(T* item) {
// Operations on item...
}
// In translation unit A:
push_item<Dog>(dog_ptr);
// In translation unit B:
push_item<Cat>(cat_ptr);
Because Dog* and Cat* are both raw machine pointers (typically 8 bytes), the generated machine instructions for push_itemHow COMDAT Folding Works
Content Comparison: The linker compares the byte streams, relocation targets, and alignment requirements of functions marked as foldable (typically COMDAT sections generated by inline functions, template instantiations, and virtual tables).
Key Benefits
The Function Pointer Quirk
The Architecture: Base-Derived Split
// --- Shared Implementation (compiled once into binary/lib) ---
class VectorPtrBase {
protected:
void** data_ = nullptr;
size_t size_ = 0;
size_t capacity_ = 0;
void grow_and_insert(size_t index, void* element) {
// All heavy buffer reallocation, index shifting,
// and boundary checks happen HERE once.
if (size_ == capacity_) {
size_t new_cap = capacity_ == 0 ? 8 : capacity_ * 2;
void** new_data = new void*[new_cap];
for (size_t i = 0; i < size_; ++i) new_data[i] = data_[i];
delete[] data_;
data_ = new_data;
capacity_ = new_cap;
}
data_[index] = element;
++size_;
}
void* get_element(size_t index) const {
return data_[index];
}
};
// --- Thin Typed Wrapper (specialization for any pointer type) ---
template <typename T>
class Vector<T*> : private VectorPtrBase {
public:
void push_back(T* val) {
// Zero-cost static cast; inlines down to a direct call to the base
grow_and_insert(size_, static_cast<void*>(val));
}
T* operator[](size_t index) const {
return static_cast<T*>(get_element(index));
}
size_t size() const { return size_; }
};








