9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

C++でもNull条件演算子的なことがしたい

Posted at

Null条件演算子とは

Null条件演算子とは、第一項がヌルポインタ (null pointer)でない場合に第二項の結果を返し、そうでない場合にnullを返す演算子である。nullでないことのチェックを回避し、メソッドチェーンやプロパティチェーンを行うために用いられる
https://ja.wikipedia.org/wiki/Null条件演算子

例えばC#の場合は以下のように?.演算子を使用する

Result  = hoge?.piyo()?.foo()?.bar();

単なるメソッドチェーンで行う場合は、過程のメソッドでもしnullが返った場合エラーになってしまうのでnullチェックが必要になる。
その場合メソッドチェーンが使用できず、一時変数やif文が大量に入るということだ。
関数にして早期リターンするのが難しい場合はネストが深くなることもあるだろう。

Piyo piyo = hoge.piyo();
if(piyo != null) {
  Foo foo = piyo.foo();
  if(foo != null) {
  ...
  }
}

C++にはNull条件演算子はない

そんな便利なNull条件演算子であるが残念ながらC++にはない。
なので、先ほどあげたように随時nullチェックをするしかない

if (auto * piyo = hoge->piyo()) {
	if (auto * foo = piyo->foo()) {
		...
	}
}

ちょっとめんどくさい。

Null条件演算子的なものを作った

本題。

実装

細かい型チェックなどは省いているが、ラムダで遅延評価にしつつ、先にnullチェックだけするようなシンプルなものを作った

safe_navigation.hpp
#pragma once

namespace safe_navigation
{
	template<class T, class U>
	auto operator | (T&& p, U&& func)->decltype(func(*p))
	{
		if (!p) {
			return nullptr;
		}
		return func(*p);
	}
}

一応これで生ポインタ、スマートポインタは対応できた。
std::optionalは未対応だが、必要な場合は返り値の型をチェックしてnulloptを返せばいい

使用方法

使いたい時はusing safe_navigation::operator|をすることで使用できるようになる。

main.cpp
int main()
{
	using safe_navigation::operator|;

	Hoge* hoge = nullptr;

	if (auto * foo = hoge
		| [](auto& hoge) { return hoge.piyo();}
     	| [](auto& piyo) { return piyo.foo(); }
	) {
		// foo something
	}

	return 0;
}

これでネストが深くなったりチェック用のローカル変数ができることもなくチェックができる
が、う~ん冗長な気もする

マクロにしてみる

え~い、マクロにしちゃえ~~

safe_navigation.hpp
#define SAFE_NAVIGATION(method) [](auto& value){return value. method ;}
#define SAFE_NAVIGATION_T(type, method) [](type & value){return value. method ;}

C++11以前はジェネリックラムダが使用できないので、型を明示できるようにもした

main.cpp
int main()
{
	using safe_navigation::operator|;

	Hoge* hoge = nullptr;

	if (auto * foo = hoge
		| SAFE_NAVIGATION_T(Hoge, piyo()) // C++11以前
		| SAFE_NAVIGATION(foo()) // C++14以降
	) {
		// foo something
	}

	return 0;
}

多少はましになったかもしれない。

まとめ

  • C++でもNull条件演算子的なものが欲しい!!
  • ラムダとか使えば無理やりそれっぽいことはできる
9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?