Date: Thu, 18 Mar 2021 18:59:32 +0200
Proposal idea:
A keyword (bikeshedding - `unique_referable`) for declaring that there is
only one way to refer to an object throughout its lifetime.
This has the following benefits:
1. Allow more aggressive copy elision rules:
```c++
pair<non_copyable, int> mrv_function()
{
unique_referable non_copyable a = {};
//fill a
return {a, 42}; //OK: copy elision is mandatory here
}
```
The rules to allow this are completely analogous to `prvalue`
materialization conversion, only we delay materialization for an lvalue.
2. Prevent dangling references.
```c++
int& get_dangling()
{
unique_referable int a = 42;
return a; //Compile error: Can't bind reference to uniquely referable
object
}
```
3. Help compiler escape analysis:
```c++
extern void foo( unique_referable int& ref);
int bar()
{
unique_referable int a = 42;
foo(a); // OK: in `foo`, the unique way to refer to the underlying
object is through `ref`
return a; //Mandatory copy elision
}
```
4. Allow destructive moves
```c++
struct A
{
A( unique_referable A&&a) = default;
};
```
This move is always destructive because `a` is the unique way to access the
underlying object and is an rvalue-reference, therefore this move is always
destructive.
Possible extensions:
1. We might need a new form of reference to work with `unique_referable`
objects.
For example:
```c++
extern void foo( unique_referable int& a, unique_referable int & b);
struct A {int a, b;};
void bar()
{
unique_referable A var{1,2};
foo(var.a, var.b); //OK
foo(var.a, var.a); //UB
}
```
I think the semantics of such references should be similar to the ones in
structured-bindings
2. If we allow a syntax that overloads on `unique_referable`ness, we can
practically achieve lazy evaluation as a language construct.
```c++
struct A
{
bool called_lazily = false;
int foo() unique_referable
{
//lazily update
called_lazily = true;
return 42;
}
int foo()
{
return 0;
}
constexpr operator A&() unique_referable& //materialization conversion
{
if ( called_lazily )
{
//do something now
}
return *this;
}
};
A bar()
{
unique_referable A a;
std::cout << a.foo(); //prints 42
return a;
}
bool baz()
{
unique_referable A a = bar(); //Copy elided
return a.called_lazily; //Calls the materialization conversion before
this line
}
```
What do you think of the idea?
A keyword (bikeshedding - `unique_referable`) for declaring that there is
only one way to refer to an object throughout its lifetime.
This has the following benefits:
1. Allow more aggressive copy elision rules:
```c++
pair<non_copyable, int> mrv_function()
{
unique_referable non_copyable a = {};
//fill a
return {a, 42}; //OK: copy elision is mandatory here
}
```
The rules to allow this are completely analogous to `prvalue`
materialization conversion, only we delay materialization for an lvalue.
2. Prevent dangling references.
```c++
int& get_dangling()
{
unique_referable int a = 42;
return a; //Compile error: Can't bind reference to uniquely referable
object
}
```
3. Help compiler escape analysis:
```c++
extern void foo( unique_referable int& ref);
int bar()
{
unique_referable int a = 42;
foo(a); // OK: in `foo`, the unique way to refer to the underlying
object is through `ref`
return a; //Mandatory copy elision
}
```
4. Allow destructive moves
```c++
struct A
{
A( unique_referable A&&a) = default;
};
```
This move is always destructive because `a` is the unique way to access the
underlying object and is an rvalue-reference, therefore this move is always
destructive.
Possible extensions:
1. We might need a new form of reference to work with `unique_referable`
objects.
For example:
```c++
extern void foo( unique_referable int& a, unique_referable int & b);
struct A {int a, b;};
void bar()
{
unique_referable A var{1,2};
foo(var.a, var.b); //OK
foo(var.a, var.a); //UB
}
```
I think the semantics of such references should be similar to the ones in
structured-bindings
2. If we allow a syntax that overloads on `unique_referable`ness, we can
practically achieve lazy evaluation as a language construct.
```c++
struct A
{
bool called_lazily = false;
int foo() unique_referable
{
//lazily update
called_lazily = true;
return 42;
}
int foo()
{
return 0;
}
constexpr operator A&() unique_referable& //materialization conversion
{
if ( called_lazily )
{
//do something now
}
return *this;
}
};
A bar()
{
unique_referable A a;
std::cout << a.foo(); //prints 42
return a;
}
bool baz()
{
unique_referable A a = bar(); //Copy elided
return a.called_lazily; //Calls the materialization conversion before
this line
}
```
What do you think of the idea?
Received on 2021-03-18 11:59:46