I have a problem where I need to bundle an ID with a reference/pointer to a value in C++, e.g.:
struct ProductWithID {
int id;
Product* product;
}
Sometimes I want to use this with a mutable Product* so the above will work, but other times I want to pass this to functions when I originally have a const Product*. But now, because I bundled the Product* into a struct, a function that previously looked like:
void HandleProduct(int id) {
const Product* product = GetProductByID(id); // API returns const Product*
MyFunction(id, product);
}
void MyFunction(int id, const Product* product);
...can not just be written as:
void HandleProduct(int id) {
const Product* product = GetProductByID(id);
MyFunction(ProductWithID{id, product}); // Error: Cannot cast const Product* to Product*
}
void MyFunction(const ProductWithID product);
...since const ProductWithID only has a Product *const not a const Product*. I could create a completely new type called ConstProductWithID and have custom constructors, including implicit cast from ProductWithID, but this feels like boilerplate.
So it would be nice if I could use template magic to simulate the language having a deep_const attribute, like the following:
template <typename T>
struct deep_const {
// ... template magic goes here ...
}
void MyFunction(deep_const<ProductWithID> product);
What deep_const would do is enumerate all the members of T and declare them fully const. Not just const in terms of pointer, but make whatever the pointers point to const as well. And then also add an implicit constructor, and maybe even aggregate initialization so it's looks, feels and smells like a regular C++ struct. Is this possible? Other suggestions welcome.