std::expectedとは #
英語: 🔗https://en.cppreference.com/w/cpp/utility/expected
日本語: 🔗https://cpprefjp.github.io/reference/expected/expected.html
std::optional
のエラー版だ。
RustのResultにも似ている。
sigillが出る #
std::expected<void, error::Error> Client::ping() {
//...
//...
// コードの最後
// コンパイルは通るけどsigillが出る
}
gdbの出力
[New Thread 0x7f86441fd6c0 (LWP 28434)]
Thread 1 "test-server" received signal SIGILL, Illegal instruction.
0x0000561252f08776 in ::client::Client::ping[abi:cxx11]() (this=0x7ffd84d8ea60) at ../common/src/client.cpp:64
64 }
よく考えると #
戻り値はお気持ちvoidだが実際はstd::expectedで、サイズがゼロなわけではないので戻り値がある関数なのにreturn
がなくておかしなことになっているということだろう。
以下はエラーがでる。
static_assert(sizeof(std::expected<void, error::Error>) == 0);
実際のstd::expected<void, error::Error>
のサイズは40バイトだった。
というわけで、明示的に
return {};
してあげたら解決した。
でもコンパイルエラーにしてくれよ!
-Weverythingとかならなんかしら出るのかもしれないがビルド環境が不完全なので、-Weverythingにするとfmt, spdlog, zpp_bitsとかのheader onlyライブラリの警告がめっちゃでてきて埋もれてしまうので早いところ個別に設定するようにしたい。
mesonでほとんどの依存プロジェクトのwarning_level
を0にして、自分のコードだけwarning_level
を3にしたら普通にでてきた。
../common/src/client.cpp: In member function ‘std::expected<void, std::__cxx11::basic_string<char> > client::Client::ping()’:
../common/src/client.cpp:65:1: error: control reaches end of non-void function [-Werror=return-type]
65 | }
| ^
コンパイラの警告を見よう(戒め)。
おまけ #
std::expected<T,void>
もだめみたい。
おとなしくoptional
を使うか1バイトの空のstructを使うしかない。
struct VoidError{};
static_assert(sizeof(VoidError)==1);
色々検証してたらどうやら単体だと1
バイトでもstd::expected
で囲むと無駄がなくなる模様。
無理やり0バイトにしたstruct(もしかしたらill-formedかも)の場合と比較してみた。
GCC 14.1 -std=c++23 -O0 -Wall -Werror
#include <expected>
#include <optional>
#include <cassert>
#include <iostream>
struct ZeroEmpty{
int dummy[0];
};
static_assert(sizeof(ZeroEmpty)==0);
struct NoMemberEmpty{
};
static_assert(sizeof(NoMemberEmpty)==1);
static_assert(sizeof(std::optional<int>)==8);
static_assert(sizeof(std::expected<int,ZeroEmpty>)==8);
static_assert(sizeof(std::expected<int,NoMemberEmpty>)==8);
std::expected<int,ZeroEmpty> f(){
return std::unexpected(ZeroEmpty{});
//return 343;
}
int main(){
auto result1=f();
assert(!result1);
std::puts("fsdfsdf");
}