mirror of
https://github.com/bspeice/speice.io
synced 2024-11-14 14:08:09 -05:00
Forcing methods to use const
This commit is contained in:
parent
ee39f7bc43
commit
0ad37c23e0
@ -26,8 +26,12 @@ Same name and parameter signature, but return different types - `AsRef`
|
|||||||
|
|
||||||
Rust has some types named by the compiler, but inaccessible in traits; can't return `impl SomeTrait`
|
Rust has some types named by the compiler, but inaccessible in traits; can't return `impl SomeTrait`
|
||||||
from traits. Can return `impl Future` from free functions and structs, but traits can't use
|
from traits. Can return `impl Future` from free functions and structs, but traits can't use
|
||||||
compiler-generated types (associated types still need to name the type). C++ doesn't appear to have
|
compiler-generated types (associated types still need to name the type). Can have traits return
|
||||||
the same restrictions.
|
references (and use vtable, so no longer statically polymorphic), but typically get into all sorts
|
||||||
|
of lifetime issues. Can also use `Box` trait objects to avoid lifetime issues, but again, uses
|
||||||
|
vtable.
|
||||||
|
|
||||||
|
C++ doesn't appear to have the same restrictions, mostly because the "contract" is just duck typing.
|
||||||
|
|
||||||
# Require static methods on a class?
|
# Require static methods on a class?
|
||||||
|
|
||||||
@ -159,11 +163,67 @@ public:
|
|||||||
|
|
||||||
`std::is_const` should be able to handle it: https://en.cppreference.com/w/cpp/types/is_const
|
`std::is_const` should be able to handle it: https://en.cppreference.com/w/cpp/types/is_const
|
||||||
|
|
||||||
# Move/consume `self` as opposed to `&self`?
|
---
|
||||||
|
|
||||||
Not exactly polymorphism, but is a significant feature of Rust trait system. Is there a way to force
|
`is_const` could be used to declare the entire class is const, but don't think you could require
|
||||||
`std::move(object).method()`? C++ can still use objects after movement makes them invalid, so not
|
const-ness for only certain methods. Can use `const_cast` to assert "constness" though:
|
||||||
sure that it makes conceptual sense - it's your job to prevent use-after-move, not the compiler's.
|
|
||||||
|
```c++
|
||||||
|
#include <concepts>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept ConstMethod = requires (T a) {
|
||||||
|
{ const_cast<const T&>(a).method() } -> std::same_as<std::uint64_t>;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::uint64_t my_function(ConstMethod auto a) {
|
||||||
|
return a.method();
|
||||||
|
}
|
||||||
|
|
||||||
|
class HasConst {
|
||||||
|
public:
|
||||||
|
std::uint64_t method() const {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class WithoutConst {
|
||||||
|
public:
|
||||||
|
std::uint64_t method() {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto x = HasConst{};
|
||||||
|
my_function(x);
|
||||||
|
|
||||||
|
auto y = WithoutConst{};
|
||||||
|
my_function(y);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```text
|
||||||
|
<source>:32:18: error: use of function 'uint64_t my_function(auto:1) [with auto:1 = WithoutConst; uint64_t = long unsigned int]' with unsatisfied constraints
|
||||||
|
32 | my_function(y);
|
||||||
|
| ^
|
||||||
|
<source>:9:15: note: declared here
|
||||||
|
9 | std::uint64_t my_function(ConstMethod auto a) {
|
||||||
|
| ^~~~~~~~~~~
|
||||||
|
<source>:9:15: note: constraints not satisfied
|
||||||
|
<source>: In instantiation of 'uint64_t my_function(auto:1) [with auto:1 = WithoutConst; uint64_t = long unsigned int]':
|
||||||
|
<source>:32:18: required from here
|
||||||
|
<source>:5:9: required for the satisfaction of 'ConstMethod<auto:1>' [with auto:1 = WithoutConst]
|
||||||
|
<source>:5:23: in requirements with 'T a' [with T = WithoutConst]
|
||||||
|
<source>:6:37: note: the required expression 'const_cast<const T&>(a).method()' is invalid, because
|
||||||
|
6 | { const_cast<const T&>(a).method() } -> std::same_as<std::uint64_t>;
|
||||||
|
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
|
||||||
|
<source>:6:37: error: passing 'const WithoutConst' as 'this' argument discards qualifiers [-fpermissive]
|
||||||
|
<source>:22:19: note: in call to 'uint64_t WithoutConst::method()'
|
||||||
|
22 | std::uint64_t method() {
|
||||||
|
| ^~~~~~
|
||||||
|
```
|
||||||
|
|
||||||
# Local trait implementation of remote data type?
|
# Local trait implementation of remote data type?
|
||||||
|
|
||||||
@ -234,10 +294,6 @@ Alternately, `ClientExt: AnotherTrait` implementations where the default `Client
|
|||||||
is used. To do this, Rust compiles the entire crate as a single translation unit, and the orphan
|
is used. To do this, Rust compiles the entire crate as a single translation unit, and the orphan
|
||||||
rule.
|
rule.
|
||||||
|
|
||||||
# Automatic markers?
|
|
||||||
|
|
||||||
Alternately, conditional inheritance based on templates?
|
|
||||||
|
|
||||||
# Trait objects as arguments
|
# Trait objects as arguments
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
@ -350,3 +406,18 @@ mostly please just use concepts.
|
|||||||
Worth acknowledging that C++ can do interesting things with `protected`, `friend`, and others, that
|
Worth acknowledging that C++ can do interesting things with `protected`, `friend`, and others, that
|
||||||
Rust can't. However, Rust can limit trait implementations to current crate ("sealed traits"), where
|
Rust can't. However, Rust can limit trait implementations to current crate ("sealed traits"), where
|
||||||
C++ concepts are purely duck typing.
|
C++ concepts are purely duck typing.
|
||||||
|
|
||||||
|
# Potentially excluded
|
||||||
|
|
||||||
|
Some ideas related to traits, but that I'm not sure sufficiently fit the theme. May be worth
|
||||||
|
investigating in a future post?
|
||||||
|
|
||||||
|
## Move/consume `self` as opposed to `&self`?
|
||||||
|
|
||||||
|
Not exactly polymorphism, but is a significant feature of Rust trait system. Is there a way to force
|
||||||
|
`std::move(object).method()`? C++ can still use objects after movement makes them invalid, so not
|
||||||
|
sure that it makes conceptual sense - it's your job to prevent use-after-move, not the compiler's.
|
||||||
|
|
||||||
|
## Automatic markers?
|
||||||
|
|
||||||
|
Alternately, conditional inheritance based on templates?
|
||||||
|
Loading…
Reference in New Issue
Block a user