1

I have a legacy function that takes an argument by T&, in modern C++ this should have been a T&& from the start.

e.g.

namespace old_space {
template<class T>
void f(T& t) {...}
}

Currently I have to do this for it to work,

MyType v = g(1);
old_space::f(v);

The function refuses to take, even in principle, a temporary rvalue.

old_space::f(g(1));

I know that there can be no leaks or dangling references and it would be actually ok to accept an rvalue. (This is because the very nature of MyType, which a simulated reference.)

I can't overload f, in the original or any namespace. Also, I want a solution that works for MyType only and not for any random type.

It occurred to me that I could have conversion operator to an lvalue.

struct MyType {
  ...
  operator MyType& operator()&& {return *this;}
};

I though it was an elegant idea, however it didn't work (f can't still capture f(g(1)). Also the compiler complained that error: converting ‘MyType’ to a reference to the same type will never use a type conversion operator [-Werror=class-conversion] if I activate warnings, which is probably true but I don't know why also.

The question is, can I adapt struct MyType in any way so that f(g(1)) is valid syntax, where g(1) generates a new value of MyType and f's signature is template<class T> void f(T&).


I also tried this, but still didn't work:

template<class T, std::enable_if_t<std::is_same<T, MyType>::value, int> =0>
operator T&() && {return *this;}
alfC
  • 14,261
  • 4
  • 67
  • 118
  • 2
    You could create an overload taking `T&&`, make a copy of the object. and pass the copy to the original `f`. If the original `f` modifies the object, then you could copy those back to the overloaded functions argument. – Some programmer dude Dec 06 '21 at 09:11
  • 3
    *"I can't overload f, in the original or any namespace."* Why? – Jarod42 Dec 06 '21 at 09:16
  • @Someprogrammerdude, yes, as I mentioned I can't overload `f`. That would be the correct solution otherwise, I agree. I wonder if there is something I can do specifically for this type. – alfC Dec 06 '21 at 09:17
  • @Jarod42, it is from a library I can't touch. – alfC Dec 06 '21 at 09:17
  • you can always add something to a namespace, in particular you can add an overload. Even if it is a legacy namespace – 463035818_is_not_an_ai Dec 06 '21 at 09:17
  • Put that overload after your `MyType`. – Jarod42 Dec 06 '21 at 09:18
  • 4
    You can create an expression that will present a temporary as an lvalue. Such as here with `unmove`: https://stackoverflow.com/a/67059296/580083. Or with a simple cast to an lvalue reference. – Daniel Langr Dec 06 '21 at 09:18
  • @Jarod42, good point, this is a simplified example, `f` in the real problem is a member function of a class in the library. If you wonder it is `operator>>` inside a Boost.Serialization Archive class. I tried as a last resort `namespace ... { template Archive& operator>>(Archive& ar, T&& t){return ar >> t;}`. But the original member function is picked up before, even if later gives an error. – alfC Dec 06 '21 at 09:20
  • 2
    If it's a library from a 3:rd party vendor, does it have updates to fix this (and probably other) problems? Do you have a support contract with the supplier of the library? Can you use it to pressure the supplier to fix it properly? And lastly, if the supplier doesn't exist any more or won't fix this problem, do you have access to the source? At least the header files should be available to you, and as a last resort you should be able to patch the source or header files you in your companies local repository to fix the issue for you. – Some programmer dude Dec 06 '21 at 09:20
  • @DanielLangr, that's basically it. I want an automatic `unmove`. – alfC Dec 06 '21 at 09:32

1 Answers1

0

You can create an overload:

void f(MyType&& t) { f(t); } // forward to lvalue version.
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • 2
    _I can't overload `f`, in the original or any namespace_ (not my -1, I feel the pain of getting a wrong answer for missing a "tiny" detail). – Enlico Dec 06 '21 at 09:16
  • 2
    Simple solution though: Give the new function a different name. – eerorika Dec 06 '21 at 09:24