Imagine some function (RetrieveResult), returning an object by pointer/reference/value - I don't know and don't want to know, because things may change. I just want to store the result, using auto and also protect that object from accidental changing in the current scope or, for example, if the object is propagated upwards.
It is quite intuitive just to write:
const auto result = RetrieveResult();
and everything works fine, if RetrieveResult returns an object by value or by reference. But if the function returns a pointer, constancy is applied to that pointer, not to the object the poiter points to. What way I still can change the object. Writing
const auto const result = ....
results in the compilation error:
duplicate 'const'
Of course, I can declare variable like this: const auto* ... const auto* const...
But that way ties me close to pointers, i.e. it isn't a universal solution.
Is it possible to preserve true constancy, and, in the same time, provide flexibility (independency of the concrete type)?
There is experimental support for this utility called std::propagate_const in the Library Fundamentals v2. You can write a type trait on top of that that does this for you (if you do not have std::propagate_const you can consider writing it yourself :))
namespace {
template <typename T, typename = std::enable_if_t<true>>
PropagateConst {
using type = T;
};
template <typename T>
PropagateConst<T, std::enable_if_t<std::is_same<
decltype(*std::declval<std::decay_t<T>>()),
decltype(*std::declval<std::decay_t<T>>())>::value>> {
using type = std::propagate_const_t<std::decay_t<T>>;
};
template <typename T>
using PropagateConst_t = typename PropagateConst<T>::type;
template <typename Type>
decltype(auto) propagate_const(Type&& in) {
return PropagateConst_t<std::add_rvalue_reference_t<Type>>{in};
}
} // <anonymous>
// then use it like this
const auto result = propagate_const(RetrieveResult());
Note that the solution I have above only checks for the presence of an operator* in the possible pointer type. You might want to consider writing a more extensive test for that.
Also note that this uses reference collapsing in the propagate_const example so expect at least a move to happen in cases where you might be expecting elision. You can optimize it based on your use case. I just thought I would outline what was in my head. Maybe that would help
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With