-
Notifications
You must be signed in to change notification settings - Fork 57
Porting QLever to Cpp17
There currently is an ongoing project to make QLever compliant with C++-17 (in particular with GCC versions starting at 8.3). This page tracks the progress and substeps of the endeavor.
- The range-v3 library has been integrated into qlever.
- In the file
src/backports/algorithm.h
(includable via#include "backports/algorithm.h
) we have implemented the namespacesql::ranges
andql::views
. These have to be used instead ofstd::ranges
andstd::views
. -
ql::views
/ql::ranges
can be configured at compile time to internally either use C++20<ranges>
orrange-v3
(via the CMake option)-DUSE_CPP_17_BACKPORTS=ON/OFF
. - Most of the uses of
std::ranges/std::views
are already replaced in the current master, only a few remaining (see this PR. - There is a CI check on
GitHub actions
that automatcially checks that QLever can be compiled with the above cmake options set toON
.
This subsection documents aspects, in which range-v3
is not a simple drop-in replacement for std::ranges
as well as the workarounds that currently should be used. The longterm solution would be to patch range-v3
, but that is currently out of scope.
-
unique
has a different interface:range-v3::unique
returns an iterator, whereasstd::ranges::unique
returns astd::ranges::subrange
. Current workaround: Simply usestd::unique(something.begin(), something.end())
. -
<range-v3>
uses a strongly typed signed integer as thedifference_type
of the implemented ranges, which cannot be directly converted to unsigned integers. This currently prevents the rewrite of the twostd::views::iota
intest/ThreadSafeQueueTest.cpp
. The short-term workaround here is to explicitly setup astd::vector
instead of theviews::iota
(it is only a test context, the memory overhead is negligible).
- Write a small standalone test program that uses the
range-v3
library and verify that (in C++-17-mode) this library in principle works on GCC 8.3. - Replace the remaining occurences of range algorithms and views (all functions and types in the namespace
std::ranges/std::views
.) - Do not replace the usage of range concepts (
std::ranges::range
,std::ranges::forward_ranges
etc.), because they additionally require the rewriting of the surrounding concept techniques.
There are some small and not so small functions and types that are new to C++20 and currently used in QLever, those can (and have to) be reimplemented in C++17. A (currently still incomplete list) follows:
- functions :
std::shift_left
,std::shift_right
,std::erase(_if)
,std::bit_cast
,std::addressof
, ... - types and classes:
std::span
.
- Most elements of the above lists can be implemented with limited effort, with the following caveats:
- The low-level utils like
bit_cast
andaddressof
can be implemented in C++17 (see the "possible implementation section" on cppreference, but they can't beconstexpr
. We have to figure out, whether this is a problem with its current usages in QLever. - For
std::span
QLever currently only uses the case of adynamic
extent, and not the full interface. Here we can start with a simple implementation that just stores two pointersbegin()
andend()
and then has the required interface.
- The replacements should be implemented in the
ql::
namespace and in header files in thesrc/backports
folder in headers with the same name as the corresponding C++ header. For example,std::span
is in the<span>
header, soql::span
should be implemented insrc/backports/span.h
. - I suggest starting with
std::span
(some typing, but conceptually simple) andstd::erase/std::erase_if
(rather simple, no implications).
-
C++20
introducesconcepts
andconstraints
that are a superior replacement of older SFINAE techniques such asstd::enable_if
andstd::void_t
. - The
range-v3
library (included in QLever) as well as QLever itself provide a set of MACROS that expand toconcepts
inC++20
-mode and tostd::enable_if
inC++17
-mode. - These macros can all be included via
#include "backports/concepts.h
.
All of the backport macros are already used in QLever, so you can also grep the codebase for example usages.
-
CPP_template
(define a template declaration with constraints on the type)
// C++20, variant a
template <std::integral T, std::floating_point F> // `std::integral` and `std::floating_point` are concepts.
class C{};
// C++20, variant b
template <typename T, typename F> requires (std::integral<T> && std::floating_point<F>)
class D{};
// The corresponding rewrite using `CPP_template`. Note the usage of `CPP_and`.
CPP_template(typename T, typename F)(requires std::integral<T> CPP_and std::floating_point<F>)
class E{};
-
CPP_and
-> See above, used to rewrite an conjunction&&
inside constraints. -
CPP_concept
define a concept
// Rewrite as follows:
template <typename T>
CPP_concept small = sizeof(T) < 3;
// This is equivalent in C++20 mode to
template <typename T>
concept small = sizeof(T) < 3;
// And in C++17 mode to
template <typename T>
static constexpr bool small = sizeof(T) < 3;
// NOTE: As soon as you rewrite one of the concepts using `CPP_concept` ,
// then you can't use it in `variant A` of the `CPP_template` example
// above anymore, but have to rewrite the template.
-
CPP_ret
(used to rewrite return types ofauto
functions), See the usage insrc/engine/sparqlExpressions/LiteralExpression.h
, there shouldn't be too much use for it. -
CPP_concept_ref
etc. (used to define concepts that userequires
clauses likerequires(T t) { t.begin(); }
has yet to be documented. -
QL_CONCEPT_OR_NOTHING
,QL_CONCEPT_OR_TYPENAME
, completely documented insrc/backports/concepts.h
, see there.
- We currently do not yet have macros to deal with templates that are declared and defined in separate places (For concepts, the constraint has to be in both places, for
enable_if
only in the declaration). Currently work withQL_CONCEPT_OR_TYPENAME
for these cases where possible, or collect the places where this is necessary, such that we can decide on how to move forward there.
- There are quite some custom concepts in the
util/TypeTraits.h
file. For each of them, make it aCPP_concept
and rewrite all its usages toCPP_template
such that the GitHub actions check with-DUSE_CPP_17_BACKPORTS=ON
works. - Rewrite the places where concepts from
std::ranges
are used (e.g.std::ranges::range
orstd::ranges::forward_range
) usingCPP_template
, then thestd::ranges
can be replaced byql::ranges
.