Die Bibliothek Boost.Optional bietet mit boost::optional
eine Klasse an, die für optionale Rückgabewerte verwendet werden kann. Damit sind Rückgabewerte von Funktionen gemeint, die unter Umständen kein Ergebnis zurückgeben können. Sehen Sie sich dazu Beispiel 21.1 an, in dem eine herkömmliche Lösung ohne Boost.Optional zum Tragen kommt.
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>
int get_even_random_number()
{
int i = std::rand();
return (i % 2 == 0) ? i : -1;
}
int main()
{
std::srand(static_cast<unsigned int>(std::time(0)));
int i = get_even_random_number();
if (i != -1)
std::cout << std::sqrt(static_cast<float>(i)) << '\n';
}
Im Beispiel 21.1 wird eine Funktion get_even_random_number()
verwendet, die eine gerade Zufallszahl zurückgeben soll. Dazu wird auf die Funktion std::rand()
aus der Standardbibliothek zugegriffen. Die Implementation von get_even_random_number()
ist recht naiv: Gibt std::rand()
eine gerade Zufallszahl zurück, wird diese als Rückgabewert von get_even_random_number()
weitergereicht. Ist die von std::rand()
generierte Zufallszahl ungerade, wird -1 zurückgegeben.
So wie get_even_random_number()
implementiert ist, bedeutet -1, dass keine gerade Zufallszahl generiert werden konnte und zurückgegeben werden kann. Die Funktion get_even_random_number()
kann nicht garantieren, dass eine gerade Zufallszahl zurückgegeben wird. Der Rückgabewert ist optional.
Viele Funktionen verwenden spezielle Werte wie -1, um anzugeben, dass kein Ergebnis zurückgegeben werden kann. So gibt zum Beispiel die Methode find()
der Klasse std::string
den speziellen Wert std::string::npos zurück, wenn ein Substring nicht gefunden werden kann. Funktionen, deren Rückgabewert ein Zeiger ist, geben oft 0 zurück, um dem Aufrufer mitzuteilen, dass kein Ergebnis existiert.
Boost.Optional bietet mit boost::optional
eine Klasse an, die optionale Rückgabewerte deutlich macht.
boost::optional
#include <boost/optional.hpp>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>
using boost::optional;
optional<int> get_even_random_number()
{
int i = std::rand();
return (i % 2 == 0) ? i : optional<int>{};
}
int main()
{
std::srand(static_cast<unsigned int>(std::time(0)));
optional<int> i = get_even_random_number();
if (i)
std::cout << std::sqrt(static_cast<float>(*i)) << '\n';
}
Im Beispiel 21.2 hat die Funktion get_even_random_number()
mit boost::optional<int>
einen neuen Typ für den Rückgabewert erhalten. Bei boost::optional
handelt es sich um ein Template, das mit dem eigentlichen Typ des Rückgabewerts instanziiert werden muss. Um boost::optional
verwenden zu können, muss außerdem die Headerdatei boost/optional.hpp
eingebunden werden.
Generiert get_even_random_number()
eine gerade Zufallszahl, wird diese mit return
direkt zurückgeben. Sie wird automatisch in ein Objekt vom Typ boost::optional<int>
gepackt, da boost::optional
einen entsprechenden nicht-exklusiven Konstruktor anbietet. Wird keine gerade Zufallszahl generiert, wird ein leeres Objekt vom Typ boost::optional<int>
zurückgegeben. Dieses wird über den Aufruf des Standardkonstruktors erstellt.
In der Funktion main()
wird überprüft, ob i nicht leer ist. Ist dies der Fall, wird über operator*
auf die Zahl zugegriffen, die in i gespeichert ist. boost::optional
scheint daher ähnlich wie ein Zeiger zu funktionieren. Es ist jedoch wichtig, boost::optional
nicht mit einem Zeiger gleichzusetzen, da zum Beispiel der Copy-Konstruktor bei boost::optional
den im Objekt gespeicherten Wert kopiert, während ein Zeiger nicht den Wert kopiert, auf den er zeigt.
boost::optional
#include <boost/optional.hpp>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>
using boost::optional;
optional<int> get_even_random_number()
{
int i = std::rand();
return optional<int>{i % 2 == 0, i};
}
int main()
{
std::srand(static_cast<unsigned int>(std::time(0)));
optional<int> i = get_even_random_number();
if (i.is_initialized())
std::cout << std::sqrt(static_cast<float>(i.get())) << '\n';
}
Beispiel 21.3 stellt verschiedene Methoden von boost::optional
vor. So bietet die Klasse einen speziellen Konstruktor an, dem als ersten Parameter eine Bedingung übergeben werden kann. Ist die Bedingung wahr, wird ein Objekt vom Typ boost::optional
mit dem zweiten Parameter initialisiert. Ist die Bedingung falsch, wird ein leeres Objekt vom Typ boost::optional
erstellt. Dieser Konstruktor wird im Beispiel 21.3 in der Funktion get_even_random_number()
verwendet.
Über is_initialized()
kann explizit überprüft werden, ob ein Objekt vom Typ boost::optional
nicht leer ist. Boost.Optional spricht von initialisierten und nicht-initialisierten Objekten – daher der Name der Methode is_initialized()
. Die Methode get()
wiederum ist gleichbedeutend mit operator*
.
#include <boost/optional.hpp>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>
using namespace boost;
optional<int> get_even_random_number()
{
int i = std::rand();
return make_optional(i % 2 == 0, i);
}
int main()
{
std::srand(static_cast<unsigned int>(std::time(0)));
optional<int> i = get_even_random_number();
double d = get_optional_value_or(i, 0);
std::cout << std::sqrt(d) << '\n';
}
Boost.Optional bietet freistehende Hilfsfunktionen wie boost::make_optional()
und boost::get_optional_value_or()
an. Während boost::make_optional()
verwendet werden kann, um ein Objekt vom Typ boost::optional
zu erzeugen, kann boost::get_optional_value_or()
aufgerufen werden, wenn ein alternativer Wert verwendet werden soll, sollte boost::optional
leer sein.
Die Funktion get_optional_value_or()
wird auch als Methode von boost::optional
angeboten. Sie heißt dann get_value_or()
.
Boost.Optional bietet mit boost/optional/optional_io.hpp
auch eine Headerdatei an, die Stream-Operatoren überlädt, um Objekte vom Typ boost::optional
zum Beispiel direkt auf die Standardausgabe ausgeben zu können.