문제

(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.

다른 팁

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...
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top