C++ - how to return a prvalue by reference?

落花浮王杯 提交于 2019-12-23 04:26:47

问题


So I'm implementing a native arrays wrapper which will allow such to be passed as function arguments and to be returned. I'm having a trouble however with casting it to a native array as native arrays can't be returned. As an replacement I decided to use 'rvalue' reference return type of the casting operator but this will not act correctly because if I want to bind the returned object into an 'rvalue' reference in order to extend it's life-time this won't happen as it's an 'xvalue' and not 'prvalue'. Is there any solution for the problem? Maybe some 'prvalue' cast? Or if there is some other way to implement this implicit cast to 'array'?

The class:

template<typename type>
struct tmp
{
    tmp() {}
    tmp(const tmp &) = default;
    tmp(const type & arg) : tmp(*(const tmp*)arg) {}

    && operator type() && {return static_cast<type&&>(d);}

    ~tmp () { cout << "tmp destructor" << endl; }

    type d;

};

And the code that uses it:

tmp<tmp<int [4]>> Func() // used 'tmp<int [4]>' instead of array to track object destruction (but normally it should be an native array type
{
    return tmp<tmp<int [4]>>();
}

int main()
{
    tmp<int [4]> &&tmp1 = Func(); //implicit cast (from 'tmp<tmp<int [4]>>') to 'tmp<int [4]>', calls tmp::operator type()

    cout << "Here" << endl;

    return 0;
}

The program output:

tmp destructor

tmp destructor

Here

As you see the return value of the cast operator is not extended.

Life example.


回答1:


A prvalue is an rvalue that is not an xvalue, aka "a temporary object or subobject thereof, or a value that is not associated with an object."

You cannot create an array that is a a temporary object (12.2), nor can you create an array value that is not associated with an object.

For an array to be a prvalue, that leaves a subobject thereof of a temporary object.

So a tmp:

template<typename type>
struct tmp
{
  tmp() {}
  tmp(const tmp &) = default;
  tmp(tmp &&) = default;
  tmp(const tmp &&o):tmp(o) {}
  tmp(tmp &o):tmp(const_cast<tmp const&>(o)){}

  template<class... Ts>
  tmp(Ts&&...ts) : v{std::forward<Ts>(ts)...} {}

  ~tmp () { std::cout << "tmp destructor\n"; }

  type v;
};

A wrap_as_tmp:

template<class X, class... Ts>
tmp<X> wrap_as_tmp(Ts&&... ts)
{
  return {std::forward<Ts>(ts)...};
}

to track destruction we use noisy:

struct noisy {
  ~noisy() { std::cout << "bang\n"; }
};

Then test:

int main() {
  auto&& x = wrap_as_tmp<noisy[4]>().v;
  std::cout << "There\n";
}

and note that There outputs before the noisy objects explode.

live example

Note the use of .v at the end of the function call.

If your goal is to avoid that, too bad, you cannot.



来源:https://stackoverflow.com/questions/27280293/c-how-to-return-a-prvalue-by-reference

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!