Thread overview | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
January 31, 2016 Declaring rvalue function arguments | ||||
---|---|---|---|---|
| ||||
I know I can mark an argument ref to require lvalues, so I'm wondering whether there is an equivalent for rvalues; that is, is there a way to specify that an argument to a function MUST be an rvalue? For example, in C++ I can do this: [code] void foo(int && x) {...} foo(5); // Works fine int y = 5; foo(y); // Compile error; y is not an rvalue [/code] This functionality turns out to be really useful when dealing with transferring ownership of resources. |
January 31, 2016 Re: Declaring rvalue function arguments | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matt Elkins | On Sunday, 31 January 2016 at 17:21:54 UTC, Matt Elkins wrote: > I know I can mark an argument ref to require lvalues, so I'm wondering whether there is an equivalent for rvalues; that is, is there a way to specify that an argument to a function MUST be an rvalue? > > For example, in C++ I can do this: > [code] > void foo(int && x) {...} > > foo(5); // Works fine > int y = 5; > foo(y); // Compile error; y is not an rvalue > [/code] > > This functionality turns out to be really useful when dealing with transferring ownership of resources. I am also very interested in this. I just asked this question today on SO https://stackoverflow.com/questions/35115702/how-do-i-express-ownership-semantics-in-d |
January 31, 2016 Re: Declaring rvalue function arguments | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matt Elkins | On 31.01.2016 18:21, Matt Elkins wrote:
> I know I can mark an argument ref to require lvalues, so I'm wondering
> whether there is an equivalent for rvalues; that is, is there a way to
> specify that an argument to a function MUST be an rvalue?
>
> For example, in C++ I can do this:
> [code]
> void foo(int && x) {...}
>
> foo(5); // Works fine
> int y = 5;
> foo(y); // Compile error; y is not an rvalue
> [/code]
>
> This functionality turns out to be really useful when dealing with
> transferring ownership of resources.
I don't know if this works in all cases, but it passes that simple test:
----
@disable void foo(ref int x);
void foo(int x) {}
void main()
{
foo(5); /* works */
int y = 5;
foo(y); /* error */
}
----
|
January 31, 2016 Re: Declaring rvalue function arguments | ||||
---|---|---|---|---|
| ||||
Posted in reply to anonymous | On Sunday, 31 January 2016 at 17:42:19 UTC, anonymous wrote:
> On 31.01.2016 18:21, Matt Elkins wrote:
>> I know I can mark an argument ref to require lvalues, so I'm wondering
>> whether there is an equivalent for rvalues; that is, is there a way to
>> specify that an argument to a function MUST be an rvalue?
>>
>> For example, in C++ I can do this:
>> [code]
>> void foo(int && x) {...}
>>
>> foo(5); // Works fine
>> int y = 5;
>> foo(y); // Compile error; y is not an rvalue
>> [/code]
>>
>> This functionality turns out to be really useful when dealing with
>> transferring ownership of resources.
>
> I don't know if this works in all cases, but it passes that simple test:
>
> ----
> @disable void foo(ref int x);
> void foo(int x) {}
>
> void main()
> {
> foo(5); /* works */
> int y = 5;
> foo(y); /* error */
> }
> ----
The problem is that x will be copied afaik which is not what you want if you want to deal with ownership.
|
January 31, 2016 Re: Declaring rvalue function arguments | ||||
---|---|---|---|---|
| ||||
Posted in reply to anonymous | On Sunday, 31 January 2016 at 17:42:19 UTC, anonymous wrote:
> I don't know if this works in all cases, but it passes that simple test:
>
> ----
> @disable void foo(ref int x);
> void foo(int x) {}
>
> void main()
> {
> foo(5); /* works */
> int y = 5;
> foo(y); /* error */
> }
> ----
My fault, I should have better explained the situation I'm running into. I've boiled it down to this:
[code]
struct Foo
{
@disable this(this);
@disable void opAssign(ref Foo);
void opAssign(Foo foo) {}
}
unittest
{
void bar(Foo foo)
{
Foo foo1;
foo1 = foo; // Fails to compile here
}
Foo makeFoo() {return Foo();}
bar(Foo());
}
[/code]
[output]
Error: function Foo.opAssign is not callable because it is annotated with @disable
[/output]
Note that if I don't declare and assign foo1 on separate steps it yells at me for the post-blit constructor being disabled, which is reasonable. But it seems like the rvalue assignment operator should work...
|
January 31, 2016 Re: Declaring rvalue function arguments | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matt Elkins | Errr, ignore the makeFoo() line. Left that in by accident, has no bearing on the issue. |
January 31, 2016 Re: Declaring rvalue function arguments | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matt Elkins | On Sunday, 31 January 2016 at 17:55:53 UTC, Matt Elkins wrote:
> Errr, ignore the makeFoo() line. Left that in by accident, has no bearing on the issue.
Ok, I think I understand why this doesn't work, at least. The Foo passed into bar() is, of course, an lvalue itself.
So I can achieve this with a new bar(), like so:
[code]
void bar(Foo foo)
{
import std.algorithm.mutation;
Foo foo1 = move(foo);
}
[/code]
|
January 31, 2016 Re: Declaring rvalue function arguments | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matt Elkins | On Sunday, 31 January 2016 at 17:55:53 UTC, Matt Elkins wrote: > Errr, ignore the makeFoo() line. Left that in by accident, has no bearing on the issue. I have found an interesting SO answer http://stackoverflow.com/a/35114945/944430 This would explain everything that we would need. I am just not 100% sure if everything he says is actually true. |
January 31, 2016 Re: Declaring rvalue function arguments | ||||
---|---|---|---|---|
| ||||
Posted in reply to maik klein | On Sunday, 31 January 2016 at 17:48:53 UTC, maik klein wrote:
> The problem is that x will be copied afaik which is not what you want if you want to deal with ownership.
I think that can be solved by wrapping the resource in a struct that deals with passing the ownership. Here is the one I am using right now:
[code]
struct ResourceHandle(T, alias Deleter, T Default = T.init)
{
// Constructors/Destructor
this(in T handle) {m_handle = handle;}
@disable this(this);
~this() {Deleter(m_handle);}
// Operators
@disable void opAssign(ref ResourceHandle lvalue);
ref ResourceHandle opAssign(ResourceHandle rvalue) {swap(m_handle, rvalue.m_handle); return this;}
// Methods
@property T handle() const {return m_handle;}
@property T handle(T handle) {Deleter(m_handle); m_handle = handle; return m_handle;}
T release() {T result = m_handle; m_handle = Default; return result;}
private:
T m_handle = Default;
}
[/code]
|
January 31, 2016 Re: Declaring rvalue function arguments | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matt Elkins | On Sunday, 31 January 2016 at 18:02:19 UTC, Matt Elkins wrote:
> Here is the one I am using right now:
Actually, here is the whole module in case you are interested in the unittests/usage:
[code]
import std.algorithm;
import std.traits;
struct ResourceHandle(T, alias Deleter, T Default = T.init)
{
// Constructors/Destructor
this(in T handle) {m_handle = handle;}
@disable this(this);
~this() {Deleter(m_handle);}
// Operators
@disable void opAssign(ref ResourceHandle lvalue);
ref ResourceHandle opAssign(ResourceHandle rvalue) {swap(m_handle, rvalue.m_handle); return this;}
// Methods
@property T handle() const {return m_handle;}
@property T handle(T handle) {Deleter(m_handle); m_handle = handle; return m_handle;}
T release() {T result = m_handle; m_handle = Default; return result;}
private:
T m_handle = Default;
}
@nogc @safe nothrow unittest
{
static uint destroyedCount;
static uint lastDestroyed;
alias RH = ResourceHandle!(uint, (uint resource){if (resource != uint.init) {lastDestroyed = resource; ++destroyedCount;}});
// Test basic resource cleanup
assert(destroyedCount == 0);
assert(lastDestroyed != 7);
{auto handle0 = RH(7);}
assert(destroyedCount == 1);
assert(lastDestroyed == 7);
// Test releasing
{
auto handle0 = RH(8);
assert(handle0.handle == 8);
assert(handle0.release() == 8);
assert(handle0.handle == uint.init);
assert(destroyedCount == 1);
assert(lastDestroyed == 7);
}
assert(destroyedCount == 1);
assert(lastDestroyed == 7);
{
// Test that copying and lvalue assignment are disabled
auto handle0 = RH(5);
static assert (!__traits(compiles, {auto handle1 = handle0;}));
static assert (!__traits(compiles, {RH handle1; handle1 = handle0;}));
// Test that rvalue assignment works
auto makeRH(uint value) {return RH(value);}
handle0 = makeRH(3);
assert(destroyedCount == 2);
assert(lastDestroyed == 5);
}
assert(destroyedCount == 3);
assert(lastDestroyed == 3);
// Test setting in static array
{
RH[3] handles;
handles[0] = RH(9);
assert(destroyedCount == 3);
assert(lastDestroyed == 3);
}
assert(destroyedCount == 4);
assert(lastDestroyed == 9);
// Test setting to resource directly
{
auto handle0 = RH(11);
assert(destroyedCount == 4);
assert(lastDestroyed == 9);
assert(handle0.handle == 11);
handle0.handle = 12;
assert(destroyedCount == 5);
assert(lastDestroyed == 11);
assert(handle0.handle == 12);
}
assert(destroyedCount == 6);
assert(lastDestroyed == 12);
}
[/code]
|
Copyright © 1999-2021 by the D Language Foundation