0

In the below code the variable a is no longer used after the call to xtransform, is there some reason that it cannot be (or simply is not) implicitly converted to an rvalue reference at the time of that call?

#include <memory>
#include <algorithm>
#include <array>


template <typename O, typename I, size_t SZ, typename F>
auto xtransform(std::unique_ptr<std::array<I, SZ>>&& in, F&& func)
{
    static_assert(
        (sizeof(O)==sizeof(I)) &&
        (alignof(O)==alignof(I)),
        "Input and Output types are not compatible");
    std::unique_ptr<std::array<O, SZ>> out {reinterpret_cast<std::array<O, SZ>*>(in->begin())};
    std::transform(in->begin(), in->end(), out->begin(), func);
    return out;
}

int main(void)
{
    auto a = std::make_unique<std::array<long, 1000>>();
    auto b = xtransform<double>(a, [](long in) { return double(in); });  // a has to be explicitly moved here
}

I was hoping to use the implicit conversion behavior to help the user out. In this case I was hoping the implicit conversion to an rvalue reference would work, but if the user continued to use the object (a) after the call to xtransform, the conversion wouldn't be allowed and it would fail to compile. This would protect the user from bugs caused by the memory reuse enabled by xtransform. It would also informing the user of a need to copy, making expensive operations more explicit.

ktb
  • 1,498
  • 10
  • 27
  • @Nicol Bolas Yes, this is a duplicate, however, it brings up a potential improvement to the standard. There is no conceptual reason it *shouldn't* be able to do the conversion, just that it might not be *preferred*. So in cases where it is the only option available, it could do the conversion rather than fail. Or am I totally off base? – ktb Nov 08 '19 at 18:39
  • "*There is no conceptual reason it shouldn't be able to do the conversion*" That all depends. Do you think that the meaning of an expression should be based on where it appears in a function (ignoring questions of whether identifiers are in scope)? Because that's what you're talking about here: the validity of the expression would be based on what appears beneath the expression itself. The idea that [an expression's validity should not be based on what appears later](https://stackoverflow.com/a/15387565/734069) is a perfectly valid concept, and thus is a "conceptual reason" to prevent it. – Nicol Bolas Nov 08 '19 at 19:54
  • @ktb if there are overloads of the function for both rvalue and lvalue reference argument, then implicitly converting to an rvalue would _change what function gets called_. If this implicit conversion could be disabled by further use of the variable later in the same function, then that would mean that you could not reason about what an expression does without reading the _entire_ context surrounding it. I think we'd all be sad if this was reality. – Chris Uzdavinis Nov 08 '19 at 20:02
  • I fail to see either of your points. Unless rvalue references have no real meaning outside of convention, which I'm guessing is the real point here. We aren't just talking about "any ol' expression" that would become invalid based on what appears later, but an expression that invalidates an object. That is, I'm assuming, what rvalue references are meant to encode. If you use that invalidated object later, something is wrong. Invalidation by casting to rvalue reference can be determined statically, I'd rather not have to wait until runtime to see I'm using an invalidated object. – ktb Nov 08 '19 at 20:29
  • Of course, currently, you can use an object after passing it to a function by rvalue reference. Perhaps that should be a compilation failure? Or maybe rvalue references are meaningless except by convention. And that's my hang up. – ktb Nov 08 '19 at 20:33
  • Okay, after some more thought I see why you can't statically invalidate an object, references, pointers, etc would also have to be invalidated and determining that staically is impossible. – ktb Nov 08 '19 at 20:40

0 Answers0