Hello! And sorry for my english.
Let's consider that example, taking from one comments of the Eric Niebler's blog:
std::vector<bool> v{true,false,true};
for (auto i : v)
i = false; // (1)
The range-based for is modifying the vector, since it's taking copies of the proxy object. However, the proxy object is a reference-wrapper. And what is the property of a reference? That if I need to get a copy, a need a copy of the value type, not the reference type. I have reading some attempts to propose auto deduction rules and the sort, but the seems not satisfaying But, why not adding to the language the posibility of specifying a dual type according if they is being used as reference or value type?
For example:
struct Iterator
{
// other code
value_type T;
reference R;
reference ! value_type operator*() const { return reference(/**/); }
};
Iterator it = container.begin();
auto& ref = *it; // Compilation error, obvious. `reference` is a rvalue.
auto const& ref = *it; // Ok, deduced as reference const&
*it = something; // Ok, the proxy still takes control.
auto value = *it; // Deduced as value_type! I have a copy of the real value!!
reference value = *it; // Compilation error?
The reference type, of course, must be convertible to the "after !" type. I have given the example with the iterator case, but it can be applied to any non-void function. The choice of `!` is because no specific reason. I just thought that it can be easier for parsers, since can't be confused with any other declarator.
For the `vector<bool>` case:
template<...>
class vector<bool, ...>
{
using value_type = bool;
using reference = bit_wrapper;
reference ! value_type operator*() const { return bit_wrapper(/**/); }
};
Or even better:
template<...>
class vector<bool, ...>
{
using value_type = bool;
using reference = bit_wrapper ! value_type;
reference operator*() const { return bit_wrapper(/**/) }
};
That way, the semantics of the `reference` and `value_type` are keep separated. It just specifies what happens when copying. The `auto` deduction rules aren't modified, since, when copying, a cast is performing. What is seen by auto is the type of the temporary object result of the casting. What changes is the effects of the copy operation, that before doing a copy, a casting is performed (I don't know what to say about moving the combined type).
auto const& ref = *it;
auto val = ref;
`ref` is deduced as `bit_wrapper ! bool const&" (a.k.a bit_wrapper const& untill is copied), and val is deduced as "bool". The idea is to specify that a type must fallback to another type when using it as value, and the type must be of course convertible to it. That shouldn't be specified in the `type` definition (inside the class). The `type` is unconnected to what types can be combined to (except that it must be convertible to, but a conversion can be available without having that posible combination in mind in the first place). You could even create variables or returning objects of those combined types.
wrapper ! value_type val(...); // I'm creating a true reference wrapper (wrapper, by itself, is not a true reference till combined with its value type).
auto v = val; // v is value_type.
But it's harder to say what will be the different rules about the combined types in the different expressions it could appear, and I know that is a very big change for a very specific case (proxy "things"), but I think, if the rules are well design and very enclosed to only what it's needed, maybe it can be, maybe and at least, arguable, without touching current STL's algorithm implementations.