vak: (Знайка)
[personal profile] vak
Устав от сложных концепций, глянем что-нибудь простое, скажем тип Option<T>. Это контейнер на одно значение произвольного типа, которое может отсутствовать. В Си++17 появился практически идентичный класс std::optional. Но мы попросим Грок состряпать нам решение, максимально близкое к Rust.

Question: Please implement type Option in C++, making it as close to Rust as possible, but still convenient for C++.

Let's create a C++ implementation of Rust's Option type. In Rust, Option is an enum that represents either Some(value) or None, used for handling cases where a value might be absent. Here's a C++ version that mimics this behavior while adapting to C++ idioms:
#include <utility>
#include <stdexcept>

template <typename T>
class Option {
private:
bool has_value;
union {
T value;
};

public:
// Constructors
Option() : has_value(false) {}

explicit Option(const T& val) : has_value(true), value(val) {}

explicit Option(T&& val) : has_value(true), value(std::move(val)) {}

// Copy constructor
Option(const Option& other) : has_value(other.has_value) {
if (has_value) {
new(&value) T(other.value);
}
}

// Move constructor
Option(Option&& other) noexcept : has_value(other.has_value) {
if (has_value) {
new(&value) T(std::move(other.value));
other.has_value = false;
}
}

// Destructor
~Option() {
if (has_value) {
value.~T();
}
}

// Assignment operators
Option& operator=(const Option& other) {
if (this != &other) {
if (has_value) {
value.~T();
}
has_value = other.has_value;
if (has_value) {
new(&value) T(other.value);
}
}
return *this;
}

Option& operator=(Option&& other) noexcept {
if (this != &other) {
if (has_value) {
value.~T();
}
has_value = other.has_value;
if (has_value) {
new(&value) T(std::move(other.value));
other.has_value = false;
}
}
return *this;
}

// Static methods to create Some and None
static Option Some(const T& val) { return Option(val); }
static Option None() { return Option(); }

// Check if contains value
bool is_some() const { return has_value; }
bool is_none() const { return !has_value; }

// Access value (unsafe - throws if None)
T& unwrap() {
if (!has_value) {
throw std::runtime_error("Called unwrap on None");
}
return value;
}

const T& unwrap() const {
if (!has_value) {
throw std::runtime_error("Called unwrap on None");
}
return value;
}

// Access with default value
T unwrap_or(const T& default_value) const {
return has_value ? value : default_value;
}

// Get value or compute default
template <typename F>
T unwrap_or_else(F&& func) const {
return has_value ? value : func();
}
};

// Helper function to make creation more convenient
template <typename T>
Option<T> some(const T& value) {
return Option<T>::Some(value);
}

template <typename T>
Option<T> none() {
return Option<T>::None();
}
This implementation:
  1. Uses a template class to work with any type T, like Rust's generic Option<T>
  2. Uses a union to store the value efficiently, only constructing it when needed
  3. Provides Rust-like methods:
    • is_some() and is_none() for checking state
    • unwrap() for direct access (throws on None)
    • unwrap_or() for providing a default
    • unwrap_or_else() for computing a default
  4. Includes proper C++ memory management with constructors, destructor, and assignment operators
  5. Offers convenient some() and none() helper functions
  6. Handles both copy and move semantics
Key differences from Rust's Option:
  1. Uses exceptions instead of panic for unwrap on None (more C++-idiomatic)
  2. No pattern matching (C++ doesn't have it natively)
  3. Requires explicit template parameters in some cases due to C++ syntax
  4. Memory management is explicit (Rust handles this automatically)
The union approach saves space like Rust's implementation, but requires careful handling of construction and destruction. This version is reasonably safe and efficient while maintaining a Rust-like feel adapted to C++.

You could use it like this:
Option<std::string> find_name(int id) {
if (id == 1) {
return some(std::string("Alice"));
}
return none<std::string>();
}
It’s not a perfect replica of Rust’s Option due to language differences, but it captures the core concept while being practical in C++.

Date: 2025-03-02 06:03 (UTC)
juan_gandhi: (Default)
From: [personal profile] juan_gandhi
Стандартная вещь - но что там за union? Не понимаю.

Date: 2025-03-02 11:05 (UTC)
juan_gandhi: (Default)
From: [personal profile] juan_gandhi
А, так это специфика С++. В джаве ничего такого нету. Но это дефект, наверно. У вас тут в си копируется значение. В джаве глубокая копия - это ой.

Мудро, мудро. И правильно.

Date: 2025-03-02 15:48 (UTC)
From: [personal profile] nz

на этом можно сэкономить

Дело даже не в экономии: если значения нет, то его по определению конструировать нельзя.
Тип T неизвестен, может там в конструкторе сайд еффекты какие.

То, что оно знает про трюк с union и не лепит туда для этого поинтер - впечатляет.