Suppose I have vector of pointers to objects of class Widget
, which are heavy objects with no owner. More often than not, my code needs to iterate over this vector, but needs only access to const Widget
.
Is it possible to write the WidgetSet class such that const WidgetSet
stores const Widget
s? I.e. the iteration over this class yields const std::shared_ptr<const Widget>&
objects.
I tried the code below, but came to various issues, highlighted in the comments:
struct Widget {
void const_method() const {}
void modify() {}
};
class WidgetSet {
std::vector<std::experimental::propagate_const<std::shared_ptr<Widget>>> _widgets;
public:
[[nodiscard]] auto begin() const { return _widgets.cbegin(); }
[[nodiscard]] auto end() const { return _widgets.cend(); }
[[nodiscard]] auto begin() { return _widgets.begin(); }
[[nodiscard]] auto end() { return _widgets.end(); }
};
void delegate_modify(const std::shared_ptr<Widget>& w) {
w->modify();
}
void exposed_delegate_modify(std::experimental::propagate_const<std::shared_ptr<Widget>>& w) {
//I need to prevent this from compiling and I would not like clients to use types have std::experimental::propagate_const in its name.
w->modify();
}
void delegate_test(const std::shared_ptr<const Widget>& w) {
w->const_method();
// w->modify(); // error, as expected.
}
void test(const WidgetSet cws, WidgetSet ws) {
for(const auto& w: cws) {
w->const_method(); // OK
// w->modify(); // error, as expected.
delegate_modify(get_underlying(w)); //surprise! this compiles, but shouldn't: w is const!
// exposed_delegate_modify(w); // error, as expected.
// delegate_test(w); // error: No matching function for call.
}
}
I also need this class to interoperate with existing functions that accept std::shared_ptr<const Widget>
and std::shared_ptr<Widget>
which do not depend on the experimental::propagate_const
.