C++ 4 Min. Lesezeit

Wie fortgeschrittene C++-Entwickler modernen Code schrieben, bevor moderne Standards aufkamen

Diesen Artikel teilen
How Advanced C++ Developers Wrote Modern Code Before the Rise of Modern Standards

Vor C++11 und den nachfolgenden Standards mussten erfahrene C++-Entwickler kreative Wege finden, um modernen, wartbaren und effizienten Code zu schreiben. Die folgenden Beispiele zeigen, wie sie Funktionen umsetzten, die später standardisiert wurden:

1 – shared_ptr

Smart Pointer wurden in C++ schon lange eingesetzt, häufig über eigene Implementierungen oder Bibliotheken wie Boost. Für viele C++-Entwickler bedeutete die Einführung von shared_ptr und anderen Smart Pointern in der Standardbibliothek daher vor allem die Standardisierung von Werkzeugen, die sie bereits verwendeten.

#include <boost/shared_ptr.hpp>
boost::shared_ptr<int> p(new int(10));

2 – Range-based for-Schleife

BOOST_FOREACH ist ein von Boost bereitgestelltes C++-Makro, das die Iteration über Container vereinfacht. Es existierte bereits vor der mit C++11 eingeführten Range-based for-Schleife und ermöglichte saubereren und besser lesbaren Code.

#include <boost/foreach.hpp>
#include <vector>
#include <iostream>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    BOOST_FOREACH(int& x, vec) {
        std::cout << x << " ";
    }
    return 0;
}

3 – C++ Concepts

Vor Concepts wurde enable_if aus <type_traits> verwendet, um Funktionstemplates und Klassenspezialisierungen abhängig von Traits bedingt zu aktivieren. Dieser Ansatz ist ausführlicher und schwerer zu lesen und führt häufig zu komplexer Syntax.

template <typename T>
std::enable_if_t<std::is_integral_v<T>, T> add(T a, T b) {
    return a + b;
}

4 – Lambda-Ausdrücke

Die Boost-Lambda-Bibliothek ermöglichte es, kleine unbenannte Funktionsobjekte (Lambdas) in C++ zu erzeugen und direkt dort einzusetzen, wo ein Funktionsobjekt oder Funktor benötigt wird. Das ist besonders bei kurzen Operationen praktisch und macht Code kompakter und besser lesbar.

#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <algorithm>
#include <vector>

int main() {
    using namespace boost::lambda;
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::for_each(vec.begin(), vec.end(), std::cout << (_1 * 2) << " ");
    return 0;
}

Dieser Code gibt jedes Element des Vektors mit 2 multipliziert aus.

5 – constexpr

Bevor constexpr mit C++11 eingeführt wurde, griffen Entwickler häufig auf Boost zurück, um eine ähnliche Auswertung konstanter Ausdrücke zur Compile-Zeit zu erreichen. Boost bietet verschiedene Hilfsmittel und Techniken, mit denen sich das Verhalten von constexpr.

Obwohl es kein direkter Ersatz ist, kann BOOST_STATIC_ASSERT für Assertions zur Compile-Zeit eingesetzt werden und so sicherstellen, dass bestimmte Bedingungen bereits beim Kompilieren erfüllt sind.

Beispiel:

#include <boost/static_assert.hpp>

BOOST_STATIC_ASSERT(sizeof(int) == 4);

Boost.MPL stellt ebenfalls Werkzeuge für Berechnungen zur Compile-Zeit bereit, mit denen sich ein ähnliches Verhalten wie bei constexpr in der Template-Metaprogrammierung erzielen lässt.

Beispiel:

#include <boost/mpl/int.hpp>
#include <boost/mpl/plus.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/static_assert.hpp>

namespace mpl = boost::mpl;

typedef mpl::int_<3> three;
typedef mpl::int_<4> four;
typedef mpl::plus<three, four>::type seven;

BOOST_STATIC_ASSERT((mpl::equal_to<seven, mpl::int_<7>>::value));

Schließlich ist Boost.Hana eine moderne Metaprogrammierungsbibliothek mit leistungsfähigeren und flexibleren Compile-Time-Funktionen, ähnlich wie constexpr.

Beispiel:

#include <boost/hana.hpp>
#include <iostream>

namespace hana = boost::hana;

constexpr auto sum = hana::int_c<3> + hana::int_c<4>;

int main() {
    std::cout << sum << std::endl; // Outputs: 7
    return 0;
}

6 – Type Traits

C++11: std::is_same, std::enable_if, etc.
Boost: boost::is_same, boost::enable_if, etc.

  • Boost stellte Type Traits und SFINAE-Hilfsmittel für die Template-Metaprogrammierung bereit.

Beispiel:

#include <boost/type_traits.hpp>
boost::is_same<int, int>::value; // true

7 – Statische Assertions

C++11: static_assert
Boost: BOOST_STATIC_ASSERT

  • Boost ermöglichte Assertions zur Compile-Zeit, um Fehler frühzeitig zu erkennen.

Beispiel:

#include <boost/static_assert.hpp>
BOOST_STATIC_ASSERT(sizeof(int) == 4);

8 – Reguläre Ausdrücke

C++11: std::regex
Boost: boost::regex

  • Boost stellte eine leistungsfähige Bibliothek für reguläre Ausdrücke bereit.

Beispiel:

#include <boost/regex.hpp>
boost::regex re("^[0-9]+$");

9 – Tupel

C++11: std::tuple
Boost: boost::tuple

  • Boost bot eine Möglichkeit, mehrere Werte aus einer Funktion zurückzugeben.

Beispiel:

#include <boost/tuple/tuple.hpp>
boost::tuple<int, std::string> t(1, "example");

10 – Chrono

C++11: std::chrono
Boost: boost::chrono

  • Boost stellte Hilfsmittel für Zeitdauern und Uhren bereit.

Beispiel:

#include <boost/chrono.hpp>
boost::chrono::steady_clock::time_point start = boost::chrono::steady_clock::now();

11 – Threading

C++11: std::thread
Boost: boost::thread

  • Boost bot Threading-Funktionen bereits vor ihrer Standardisierung.

Beispiel:

#include <boost/thread.hpp>
boost::thread t([]{ std::cout << "Threading with Boost"; });
t.join();

Hier sind weitere Beispiele dafür, wie Boost Funktionen bereitstellte, bevor sie mit C++11 oder späteren Standards standardisiert wurden:

12 – Funktionsobjekte

C++11: std::function
Boost: boost::function

  • Boost bot boost::function zum Speichern aufrufbarer Objekte.

Beispiel:

#include <boost/function.hpp>
boost::function<int(int, int)> f = std::plus<int>();

13 – Bind

C++11: std::bind
Boost: boost::bind

  • Boost ermöglichte das Binden von Funktionsargumenten und die Erstellung partieller Funktionsanwendungen.

Beispiel:

#include <boost/bind.hpp>
auto bound_func = boost::bind(std::plus<int>(), 10, _1);
std::cout << bound_func(5); // Outputs 15

14 – Optional

C++17: std::optional
Boost: boost::optional

  • Boost stellte boost::optional für optionale Werte bereit – nützlich für Funktionen, die möglicherweise keinen Wert zurückgeben.

Beispiel:

#include <boost/optional.hpp>
boost::optional<int> maybe_value;
maybe_value = 10;
if (maybe_value) {
    std::cout << *maybe_value;
}

15 – Any

C++17: std::any
Boost: boost::any

  • Boost stellte einen typsicheren Container für einzelne Werte beliebigen Typs bereit.

Beispiel:

#include <boost/any.hpp>
boost::any value = 10;
try {
    std::cout << boost::any_cast<int>(value);
} catch (boost::bad_any_cast &) {
    std::cout << "Bad cast!";
}

16 – Variant

C++17: std::variant
Boost: boost::variant

  • Boost bot eine typsichere Union, die einen von mehreren möglichen Typen aufnehmen kann.

Beispiel:

#include <boost/variant.hpp>
boost::variant<int, std::string> var;
var = 10;
std::cout << boost::get<int>(var);

17 – Dateisystem

C++17: std::filesystem
Boost: boost::filesystem

  • Boost stellte Funktionen für Dateisystemoperationen bereit.

Beispiel:

#include <boost/filesystem.hpp>
boost::filesystem::path p("/path/to/file");
if (boost::filesystem::exists(p)) {
    std::cout << "File exists.";
}

Fazit

Boost hat historisch viele Lücken der C++-Standardbibliothek geschlossen und fortgeschrittene Funktionen sowie Hilfsmittel bereitgestellt, die später in den C++-Standard übernommen wurden. Diese Beispiele zeigen, wie Boost C++-Entwicklern schon vor der offiziellen Standardisierung in C++11 und späteren Versionen dabei half, ausdrucksstärkeren und effizienteren Code zu schreiben.

Diesen Artikel teilen