67

I have a proxy container class around a movable object, and wish the proxy to be able to implicitly yield an rvalue reference to the underlying object, but only when the proxy itself is being moved.

I believe that I will be able to implement this behaviour as per proposal n2439 "Extending move semantics to *this", but it is not yet available in a release of gcc and won't be for a while.

The code below is what I am ultimately aiming for, but is not currently possible. Until this feature is available to me, are there any equivalent workarounds?

template< class T >
struct movable_proxy {
    operator T&&() && {
        return std::move(value);
    }

    operator const T&() const& {
        return value;
    }

private:
    T value;
};
boycy
  • 1,433
  • 12
  • 24
  • 9
    I think the closest you'll be able to get is a function that does the conversion explicitly, rather than having a conversion operator, so you'd have to say `convert_proxy(p)` which is overloaded for rvalues and lvalues to return either `T&&` or `const T&` ... but that makes the use of the proxy non-transparent, which is probably not what you want – Jonathan Wakely Jan 28 '13 at 13:28
  • Indeed it isn't: although workable, it couples the client code to the proxy. A converting constructor on the wrapped type would work too, but that couples the wrapped type to it... – boycy Jan 28 '13 at 13:39
  • 1
    Oh, that proposed syntax is _groovy_. – Lightness Races in Orbit Jan 28 '13 at 13:41
  • 1
    Uh...potentially wacky idea: would complete specialisation of std::move> to return xyz&& instead of movable_proxy&& be completely insane? – boycy Jan 28 '13 at 13:42
  • 5
    I'm curious. Sorry for the lack of understanding, but I would like to get it. If you remove the newly proposed `&&` and `&` modifiers, what are you missing exactly? – Andy Prowl Jan 28 '13 at 13:49
  • 5
    For the record, [give it a go in](http://stackoverflow.com/a/8610728/560648) [clang 2.9](http://wiki.apache.org/stdcxx/C++0xCompilerSupport). – Lightness Races in Orbit Jan 28 '13 at 13:51
  • @AndyProwl: in that case, the proxy can convert into both `T const&` and `T&&`, irrespective of the value-category of the proxy itself. *I think*, the OP wants `proxy&&` to convert into `T&&` and `proxy&` into `T const&`. – Nawaz Jan 28 '13 at 13:51
  • @boycy, wouldn't you want to specialize `std::forward` not `std::move`? The latter always converts to an rvalue, even if the source wasn't an rvalue. And that only helps if the proxy object is explicitly moved/forwarded, not if it's just returned as an rvalue – Jonathan Wakely Jan 28 '13 at 13:52
  • 1
    @JonathanWakely: How does `std::forward` even make sense in this context, as `T` is not *deduced* type? – Nawaz Jan 28 '13 at 13:54
  • 1
    @Nawaz: so the wording "only when the proxy itself is movable" should be understood as "only when the proxy object is being moved", is it so? – Andy Prowl Jan 28 '13 at 13:54
  • @AndyProwl: I think so. :-) – Nawaz Jan 28 '13 at 13:54
  • Does anybody know why this feature hasn't made it into gcc? – Omnifarious Jan 28 '13 at 13:56
  • 8
    Shameless plug for the unaware: [What is "rvalue reference for *this"?](http://stackoverflow.com/questions/8610571/what-is-rvalue-reference-for-this) – Xeo Jan 28 '13 at 13:58
  • @Xeo: seven comments up! – Lightness Races in Orbit Jan 28 '13 at 14:02
  • @Non-StopTimeTravel my v3.0 clang barfs out with errors galore on standard header inclusions :-( – boycy Jan 28 '13 at 14:02
  • @JonathanWakely Ah of course, my mistake. – boycy Jan 28 '13 at 14:07
  • @AndyProwl - thanks, edited for clarification. – boycy Jan 28 '13 at 14:08
  • 14
    @Omnifarious, simply because it hasn't been implemented yet. It's the last core language feature missing, but there's far less demand (or IMHO need) for it than lambdas, rvalue references etc. It will be in GCC 4.9, possibly even 4.8.x for some `x > 0` – Jonathan Wakely Jan 28 '13 at 14:08
  • @boycy: thank you, then I do understand and can appreciate the question. +1 ;-) – Andy Prowl Jan 28 '13 at 14:10
  • @JonathanWakely (doomed by too-speedy reply bypassing brain); specialising `std::forward` won't help where client code calls `std::move(movable_proxy&)` expecting a `T&&` back. I think for `std::forward` to return the appropriate `movable_proxy` reference, i.e. to forward the proxy _as a proxy_ ,would be generally appropriate. – boycy Jan 28 '13 at 14:22
  • [With clang 3.2 it compiles just fine](http://liveworkspace.org/code/3LzsuC$2) – Constantin Feb 20 '13 at 15:18
  • You can't partially specialize function templates, and you are not allowed to put overloads into `namespace std` - sorry, but I don't think there's any way to transparently "emulate" ref-qualifiers. The client needs to do *something* other than simply `std::move(o)`. – Xeo Mar 04 '13 at 02:09
  • @Xeo: `You can't partially specialize function template` Wasn't that restriction lifted in C++11? Is this simply a matter of compiler support or am I remembering wrong? – Lightness Races in Orbit Apr 10 '13 at 13:29
  • @LightnessRacesinOrbit I think it may've been considered at some point, but no the restriction was not lifted in C++11. This is inferred through existence of 14.5.5 _Class template partial specializations_ and no equivalent for function templates than being explicitly disallowed (at least as far as I can find). – boycy Apr 10 '13 at 14:06
  • @boycy: [You're right](http://stackoverflow.com/q/3716799/560648); [they were proposed](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#229) in [n1295](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2001/n1295.asc) but ultimately rejected (and quite rightly so, since overloading does the job). – Lightness Races in Orbit Apr 10 '13 at 14:23
  • @boycy: _(cont.)_ ([I wasn't the first to think otherwise](http://stackoverflow.com/a/5101566/560648)) ([the day Xeo found this out](http://stackoverflow.com/questions/5688355/partial-specialisation-of-member-function-with-non-type-parameter#comment6497058_5688412)) ([related](http://stackoverflow.com/a/5002655/560648)) – Lightness Races in Orbit Apr 10 '13 at 14:24

1 Answers1

4

Good question. I attempted writing a similar sort of proxy class recently but never achieved a good solution. The best I found was calling a member function on every use where the proxy was required to be an r-value:

ORef<T> move() {
    return ORef<T>( this->release() );
}

This changes the semantics of declaring something an r-value from std::move(proxy) to proxy.move(), but also allows the possibility of returning an object of a different type (implicitly convertible to your required type).

My coding practice using this was to always pass proxy objects as rvalues which forced manual specification of semantics (move, shared reference, copy or whatever), but that of course makes usage errors a potential problem (e.g. calling x.move() prior to the final usage of x).

dhardy
  • 8,246
  • 5
  • 32
  • 41
  • Thanks @dhardy; I ended up with the exact same proxy type with a 'release' call and the same usage errors you mention. Pity there doesn't seem to be a workaround, but I guess that does make the case for the required language extension a good one. – boycy Apr 11 '13 at 12:40