(UPDATE: This question stems from an implementation of a wrapper class passed by value for an object that has different meanings for const Foo
and Foo
, a move based entirely on strong opinions from people here. Prior, I'd been passing around const Foo*
and Foo*
and when the wrapper came along I swapped that for Wrapper<Foo>
and const Wrapper<Foo>
. It is now clear that mechanical substitution doesn't make sense, and I'm going to need something more complex, such as Wrapper<Foo>
and Wrapper<const Foo>
...though I don't know how to write that properly just yet. Apologies for the misunderstanding, but I'll keep this here as I actually think it's more revealing than many questions.)
In looking into this question, it seemed to boil down to being parallel to the idea that you can't do this:
const Foo defaultFoo (6502);
const Foo theFoo (getConstFoo()); // returns const Foo for privilege reasons
if (theFoo.getBar() < 2012) {
theFoo = defaultFoo; // Error.
}
// ...you want to do const-safe methods with theFoo...
Much like references, a const value can't be retargeted. Doing the following would compile, but not be what I (in this kind of scenario) would be intending:
Foo defaultFoo (6502);
Foo& theFooRef (getFooRef());
if (theFooRef.getBar() < 2000) {
theFooRef = defaultFoo; // Not an error, but not a retarget.
}
// ...you want to do stuff with theFooRef...
It seems (from my understanding) that reference_wrapper
can work around this in the reference case, with something like:
Foo defaultFoo (6502);
std::reference_wrapper<Foo> theFooRef (getFooRef());
if (theFooRef.get().getBar() < 2000) {
theFooRef = std::ref(defaultFoo);
}
// ...do stuff with theFooRef.get() or employ implicit cast...
I'm wondering if there's a "value_wrapper
" out there which does something similar. It seems reasonable to me to want a variable which holds an item by value that is const for reasons of const-correctness...not because you aren't going to change it. (such as keeping track of the current node in a pre-order treewalk, despite only having const access to the nodes in that tree, where passing in the previous node to a function is how you get the new node)
If you wanted to be clunky, you could use std::pair<const Foo, bool>
and just ignore the bool
:
const Foo defaultFoo (6502);
std::pair<const Foo, bool> theFooBool (getConstFoo(), false);
if (theFooBool.first.getBar() < 2012) {
theFooBool = std::pair<const Foo, bool> (defaultFoo, false);
}
// ...do const-safe methods with theFooBool.first...
But is there a better way of addressing this, besides implementing my own version of "value_wrapper
"?
If you wanted to be clunky, you could use std::pair and just ignore the bool:
This clearly explains why what you want cannot be done, because this code doesn't work. I used const int
rather than const Foo
, but it's the same idea. This line is where it breaks:
theFooBool = std::pair<const Foo, bool> (defaultFoo, false);
The copy assignment operator is not declared const
, because by definition, copy-assignment is changing the object. const
is what you use when you want the object to not be changeable.
Of course, you could just use a std::reference_wrapper<const T>
, which will give you const
access, but allow for re-binding. Granted, it doesn't offer value semantics, but that's as close as you're going to get. In general, most people don't need or even want this, so it just hasn't come up yet.