gsl-lite implements the Core Guidelines support library for old compilers
ISO C++ Core Guidelines Library implementation for C++98, C++11 up
At a glance
- What is it?
- gsl-lite is a single-file, header-only implementation of the C++ Core Guidelines support library that compiles from C++98 through C++23, with span, not_null, narrow conversions and configurable contract checks, and no dependency other than the standard library. Its reason to exist is that the reference Microsoft implementation assumes a modern toolchain.
- Who is it for?
- gsl-lite fits a team maintaining code that has to compile with an older standard or an older compiler, since it gives the same span, not_null and checked conversion vocabulary the Core Guidelines describe without forcing a standard upgrade, and it also fits CUDA code, where the functions are decorated for host and device.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 64 days ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One header, every standard from C++98 onward
gsl-lite is a portable, single-file, header-only library for defensive programming, built on the C++ Core Guidelines support library specification maintained by the Standard C++ Foundation. The scope of the compatibility promise is the first thing to notice. The library was originally based on Microsoft GSL and was adapted for C++98 and C++03, and it also works when compiled as C++11, C++14, C++17, C++20 or C++23. That is the entire reason the project exists, and the difference from the default implementation of the same specification is stated plainly: gsl-lite maintains support for older versions of C++ and older compilers. The dependency situation is equally simple. There are no dependencies other than the C++ standard library, and the single header is available directly, which matters for projects whose build systems are not worth touching.
span, not_null and narrow_failfast in one namespace
The vocabulary is the point, and it is the same vocabulary the Guidelines specify. The library lives in the gsl_lite namespace, which means it does not interfere with Microsoft GSL because the two occupy different namespaces, and the documentation shows the usual practice of aliasing it locally inside your own namespace with a namespace gsl = ::gsl_lite line. A span is a contiguous range with bounds checks, a not_null is a type-encoded precondition, and narrow_failfast is a checked numeric cast. The example in the README puts them together in a way that shows why they exist as a set:
// `span<T[, Extent]>`: contiguous range with bounds checks
double mean( gsl::span<double const> values )
{
// `gsl_Expects( cond )`: precondition check
gsl_Expects( !values.empty() );
double sum = std::accumulate( values.begin(), values.end(), 0. );
// `narrow_failfast<T>( u )`: checked numeric cast
double num = gsl::narrow_failfast<double>( std::ssize( values ) );
return sum / num;
}The interesting part is the interaction. The precondition that the range is not empty is written with gsl_Expects, the size is converted with a checked cast rather than a silent narrowing, and the parameter type itself encodes the non-null expectation in the signature, so a caller sees it in the API rather than in a comment. There is also a make_unique flavour that returns a not_null wrapping a unique_ptr, which is how the type-encoded guarantee is produced rather than asserted after the fact.
Consuming it through find_package
The recommended consumption path is plain CMake, and the library ships a package configuration so this is a two line change in an existing project. The pattern is find_package with a version requirement, then linking the imported target:
cmake_minimum_required( VERSION 3.20 FATAL_ERROR )
project( my-program LANGUAGES CXX )
find_package( gsl-lite 1.1 REQUIRED )
add_executable( my-program main.cpp )
target_compile_features( my-program PRIVATE cxx_std_17 )
target_link_libraries( my-program PRIVATE gsl-lite::gsl-lite )The version requirement of 1.1 is the minimum acceptable, and the imported target name carries the namespace convention so it cannot collide with a different gsl-lite checkout. Once the build system is set up, usage is a single include, and the header path is <gsl-lite/gsl-lite.hpp>:
void printCmdArgs( gsl_lite::span<gsl_lite::zstring const> cmdArgs )
{
gsl_Expects( !cmdArgs.empty() );
auto argsWithoutExeName = cmdArgs.subspan( 1 );
for ( auto arg : argsWithoutExeName )
{
std::cout << arg << "\n";
}
}The example works through a span over the command line arguments, drops the executable name with subspan and iterates the rest. The zstring type is a convenience wrapper for a null terminated string, and the narrowing of argc into a std::size_t is done with narrow_failfast rather than a cast, which is the habit the library is trying to install.
Vcpkg, Conan and CPM for the same header
Distribution is covered three ways, and the reason is that C++ projects rarely agree on a package manager. gsl-lite is available through Vcpkg and through Conan, and it may also be obtained with CPM. The CPM route is a single line that resolves the package directly from its GitHub repository at a pinned version:
CPMFindPackage( NAME gsl-lite VERSION 1.1.1 GITHUB_REPOSITORY gsl-lite/gsl-lite )The repository ships worked examples for two of these routes, with example/with-CPM and example/with-Vcpkg as directories containing complete projects, plus example/01-basic.cpp and example/02-span.cpp as the smallest possible programs and an example/CMakeLists.txt for the build. A single header is also offered as a ready-made download, which is the path of least resistance when a project has no package manager at all, at the cost of losing the version pinning that CPM and Vcpkg give you. The project also publishes the header through the usual system package managers, so a distribution package may exist as well.
How it differs from Microsoft GSL
The differences are the specification of the project, and there are four that matter. First, older C++ and older compilers are supported, which is the headline feature and the reason the library was forked from the Microsoft original in the first place. Second, CUDA is supported, and many features can be used in CUDA kernel code, which is handled by recognising the platform at compile time and decorating some functions with __host__ and __device__ accordingly. Third, the contract and assertion checks are described as more versatile and fine-grained, and runtime enforcement is configurable through the contract checking configuration macros, so a project can choose to pay for the checks in a hot path or not. Fourth, not_null retains the copyability and movability of the wrapped type and therefore may have a moved-from state, which is a deliberate departure from a wrapper that forbids those operations. The two libraries can coexist, since one lives in gsl and the other in gsl_lite.
Checks you can switch on and off, per build
The contract checking design is what makes the library usable in production code rather than only in examples. The reference documentation has a dedicated section on contract and assertion checks and another on the configuration macros that control them, and the project positions this as a feature in its own right, listed under the reasons gsl-lite differs from the default implementation. The pattern in the code is uniform. A precondition is written with gsl_Expects, a postcondition with a corresponding macro, and the type-encoded versions such as not_null carry the guarantee in the signature so that a wrong call is a compile error rather than a runtime failure. This changes the economics of the checks. A library that always asserts is often switched off wholesale, whereas one that lets you choose per contract and per build configuration tends to survive in a codebase. The trade-off is that the decision about which checks to enable becomes a project convention, and the documentation is where that convention has to come from.
Building, testing and versioning
The repository is a conventional C++ project with the tooling you would expect. The top level holds a CMakeLists.txt and CMakePresets.json, a cmake/ directory with the package configuration, an include/ directory with the headers, a src/ directory, and a test/ directory, alongside a doc/ directory that holds the reference documentation and a migration guide. Continuous integration runs on Azure Pipelines and on AppVeyor, both with branch status badges for the master branch. The README also carries a section on using gsl-lite in libraries, which is a different problem from using it in an application, since a library that exposes gsl_lite types in its own public interface pushes that dependency onto its users, and the section exists to spell out the options. The version semantics are documented separately, and the release history shows a steady but unhurried line: v1.1.1 on 2026-08-20, v1.1.0 on 2026-03-14 and v1.0.1 on 2025-05-19, with the last push on 2026-08-20. The licence is MIT, and CHANGES.txt records what moved between versions.
Editorial conclusion
gsl-lite fits a team maintaining code that has to compile with an older standard or an older compiler, since it gives the same span, not_null and checked conversion vocabulary the Core Guidelines describe without forcing a standard upgrade, and it also fits CUDA code, where the functions are decorated for host and device. It does not fit a project that has already standardised on Microsoft GSL, and it does not fit a team that wants contract checks to be free, because the checks are there to be configured rather than ignored. Before adopting it, decide how much runtime enforcement you want, since the project documents configurable checking macros and fine-grained contract and assertion checks, read the reference documentation in doc/Reference.md and the migration guide, and pin the version you use, since the newest release is v1.1.1 from 2026-08-20 and the last push was on 2026-08-20.
Frequently asked questions
What is gsl-lite?
It is a portable, single-file, header-only library for defensive programming that implements the C++ Core Guidelines support library specification, based on Microsoft GSL and adapted for C++98 and C++03, with no dependencies beyond the C++ standard library.
Which C++ standards does gsl-lite support?
It was adapted for C++98 and C++03 and also compiles as C++11, C++14, C++17, C++20 or C++23. It is also reported to work with CUDA, where functions are decorated with __host__ and __device__.
How do I add gsl-lite to a CMake project?
Use find_package with the package name gsl-lite and a version requirement, then link the imported target gsl-lite::gsl-lite, and include the header <gsl-lite/gsl-lite.hpp>. Vcpkg, Conan and CPM are also supported.
Can gsl-lite be used alongside Microsoft GSL?
Yes. The two libraries live in different namespaces, gsl_lite against gsl, so they do not interfere with each other.
Is gsl-lite still maintained?
The repository is not archived, the last push was on 2026-08-20, and the newest release is v1.1.1 from the same day, after v1.1.0 in March 2026 and v1.0.1 in May 2025.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/gsl-lite-gsl-lite)Was this useful?