Question

(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"?

Was it helpful?

Solution

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.

OTHER TIPS

My apologies if I've overlooked something here. But since your question doesn't mention it I'm wondering if you are aware of, and have considered:

Foo defaultFoo (6502);
std::reference_wrapper<const Foo> theFooRef (getFooRef());
if (theFooRef.get().getBar() < 2000) {
    theFooRef = std::cref(defaultFoo);
}
// ...do stuff with theFooRef.get() or employ implicit cast...
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top