yohhoyの日記

技術的メモをしていきたい日記

関数戻り値の破棄を明示

プログラミング言語C++において、nodiscard属性が指定された関数に対し意図的な戻り値破棄を明示する方法。

まとめ:

  • C++23現在は、方式(3) std::ignoreへの関数戻り値代入が実践的か。*1
  • C++2c(C++26)以降は、方式(4) プレースホルダ識別子_(アンダースコア1文字)への関数戻り値代入がベター。
  • 方式(3), (4)は戻り値オブジェクトの破棄タイミングが異なることに注意。
// 戻り値の破棄をすべきでない関数
[[nodiscard]] int f() { return 42; }

f();  // コンパイラによる警告(warning)
// GCC: ignoring return value of 'int f()', declared with attribute 'nodiscard' [-Wunused-result]
// Clang:ignoring return value of function declared with 'nodiscard' attribute [-Wunused-result]

// 意図的な戻り値破棄を明示
(void)f();          // (1) OK, but...
static_cast<void>(f());  // (2) OK, but...
std::ignore = f();  // (3) OK
auto _ = f();       // (4) OK(C++2c)

各方式の問題点は下記の通り:

  • 方式(1) well-definedだが、現代では利用推奨されないCスタイルキャストを利用している。
  • 方式(2) well-definedだが、冗長な記述となっておりプログラマ意図を読み取りづらい。
  • 方式(3) C++ Core Guildlineでは方式(1),(2)の代替案とされる。Language Lawyer*2による厳密解釈では微妙とのウワサ。*3

関連URL

*1:https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es48-avoid-casts

*2:https://meta.stackoverflow.com/questions/256510/

*3:P2968R2より引用: "All major open source C++ library implementations provide a suitably implemented std::ignore allowing a no-op assignment from any object type. However, according to some C++ experts the standard doesn’t bless its use beyond std::tie."