2015-08-20 3 views
6

Мне нравится использовать std :: experimental :: optional в моем коде на C++, но проблема value_or требует, чтобы значение по умолчанию имело тот же тип, что и значение опциона.C++ эквивалент результата Rust <T, E> type?

Это не очень хорошо, если я хочу, чтобы он был опциональным, либо содержит int, либо содержит сообщение об ошибке.

Я думаю, я мог бы использовать структуру union, которая имеет логическое значение, чтобы указать, существует ли значение или это ошибка, но было бы неплохо, если бы у C++ был тип Result<T, E>, такой как Rust.

Есть ли такой тип? Почему Boost не реализовал его?

Результат действительно намного полезнее, чем вариант, и, несомненно, люди в Boost знают о его существовании. Может быть, я пойду прочитаю реализацию Rust, а затем скопирую ее на C++?

Ex:

// Function either returns a file descriptor for a listening socket or fails 
// and returns a nullopt value. 
// My issue: error messages are distributed via perror. 
std::experimental::optional<int> get_tcp_listener(const char *ip_and_port); 
// You can use value_or to handle error, but the error message isn't included! 
// I have to write my own error logger that is contained within 
// get_tcp_listener. I would really appreciate if it returned the error 
// message on failure, rather than an error value. 
int fd = get_tcp_listener("127.0.0.1:9123").value_or(-1); 
// Rust has a type which does what I'm talking about: 
let fd = match get_tcp_listener("127.0.0.1:9123") { 
    Ok(fd) => fd, 
    Err(msg) => { log_error(msg); return; }, 
} 
+2

Возможно, предложенный 'std :: expected' или другой тип« Ожидаемый », который был реализован. – chris

+0

Выражение в C++ должно иметь тип, известный во время компиляции; он не может быть ни «int», ни строкой. –

+2

Как одно полезнее, чем другое, когда они решают полностью не связанные, ортогональные проблемы? Является ли 'vector' более полезным, чем' cout'? – Barry

ответ

15

optional<T> - это асимметричный безопасный союз T и небытие (nullopt_t). Вы можете запросить, если у него есть T с explicit operator bool, и получите T с унальным *. Асимметрия означает, что опционально «предпочитает» быть T, поэтому неквалифицированные операции (например, * или оператор bool) относятся к его T.

variant<A,B,C> from paper n4218 является безопасным соединением симметричного типа A, B и C (и т.д.). boost::variant всегда включен, а std::experimental::variant - почти всегда занят.

Поскольку он симметричен, для возврата унарного * не существует уникального типа, и explicit operator bool не может сказать большой интерес, поэтому ни один из них не поддерживается.

Вместо этого вы должны посетить его или запросить его для определенных типов.

std::experimental::expected<E, T> from paper n4015 - это асимметричное соединение типа безопасного типа. Это либо T, либо E. Но как optional, он «предпочитает» быть T; у него есть explicit operator bool, который сообщает вам, является ли он T, а унарный * получает T.

В некотором смысле expected<E,T> является optional<T>, но при пустом месте вместо того, чтобы растрачивать пространство, он хранит E, который вы можете запросить.

Result<T,E> похоже на expected<E,T> (обратите внимание, что с номером n4015 порядок параметров заменяется по сравнению с Result).

+0

Wow спасибо за информацию! Вы, ребята, очень помогли! –

+1

Очень хорошее краткое объяснение опционального варианта vs, ожидаемого. Предложение о ожидании, похоже, похоже на содержание, которое я опубликовал, и ссылается на него на самом деле. Пройти через оба, вероятно, стоит того, чтобы выбрать другой вариант, который вы предпочитаете. –

3

optional конструкцией либо содержит значение некоторого типа или нет.

Возможно, вы ищете что-то вроде Boost::Variant.

Это еще не часть стандартной библиотеки, хотя что-то вроде этого может быть в конце концов.

+0

Это почти идеальное решение, но я думаю, что ожидаемый больше подходит для этой задачи. Однако ожидается, что пока не имеет стандартов. –

6

То, что вы ищете, точно соответствует ожиданию Alexandrescu. Я рекомендую слушать его разговор для глубокого понимания: https://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C. Он фактически проходит через линию выполнения, и вы можете легко написать ее самостоятельно и использовать ее после этого.

Вариант - это более общий инструмент, его можно заставить делать то, что вы хотите, но вам лучше с ожидаемым.

+0

Спасибо, это больше похоже на то, что я искал! –

+0

«вы можете легко написать его сами и использовать его после этого« да, это очень полезный разговор. в частности, я использовал его образец в проектах, где мы должны избегать бросать исключения. вы можете создать стандартную структуру «сообщение об ошибке», которая играет роль исключения, и попытаться сделать ваш класс таким, чтобы объекты, которые на самом деле являются ошибками, могут быть неявно преобразованы в другой тип или попытаться сделать это более похожим на Haskell, может быть, где вы в основном обрабатываете вещи с посетителями. если вы реализуете его самостоятельно, вместо использования варианта, вы также можете заставить его обрабатывать move_ctors правильно –

1

Если задействован не только импульс, вы можете использовать result. Это хороший контейнер с одним заголовком.

Смежные вопросы