Skip to content

Commit c51ec9e

Browse files
authored
merge develop
2 parents b9d42f9 + 2e5d1d7 commit c51ec9e

21 files changed

Lines changed: 961 additions & 270 deletions

.github/workflows/code_testing.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ jobs:
1919
- os: ubuntu-24.04
2020
compiler: clang-20
2121

22-
- os: ubuntu-24.04
23-
compiler: gcc-13
2422
- os: ubuntu-24.04
2523
compiler: gcc-14
2624
runs-on: ${{ matrix.config.os }}

CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ cmake_minimum_required(VERSION 3.24)
22

33
project(
44
dice-template-library
5-
VERSION 1.20.0
5+
VERSION 1.21.0
66
DESCRIPTION
77
"This template library is a collection of template-oriented code that we, the Data Science Group at UPB, found pretty handy. It contains: `switch_cases` (Use runtime values in compile-time context), `integral_template_tuple` (Create a tuple-like structure that instantiates a template for a range of values), `integral_template_variant` (A wrapper type for `std::variant` guarantees to only contain variants of the form `T<IX>` and `for_{types,values,range}` (Compile time for loops for types, values or ranges))."
88
HOMEPAGE_URL "https://dice-research.org/")
9-
set(POBR_VERSION 1) # Persisted Object Binary Representation
9+
set(POBR_VERSION 2) # Persisted Object Binary Representation
1010

1111
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/include/dice/template-library/version.hpp)
1212

@@ -54,7 +54,7 @@ if (WITH_BOOST)
5454
endif ()
5555

5656
set_target_properties(${PROJECT_NAME} PROPERTIES
57-
CXX_STANDARD 20
57+
CXX_STANDARD 23
5858
CXX_EXTENSIONS OFF
5959
CXX_STANDARD_REQUIRED ON
6060
)

README.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ It contains:
2727
- `inplace_polymorphic`: `std::variant`-like on-stack polymorphism based on `virtual` functions.
2828
- `type_list`: A variadic lists of types for metaprogramming.
2929
- `lazy_conditional`: Lazy conditional type selection that only instantiates the selected branch.
30+
- `format_to_ostream`: Provide an ostream `operator<<` overload for any type that is formattable with `std::format`.
31+
- `stdint`: User defined literals for fixed size integers.
3032

3133
## Usage
3234

@@ -168,19 +170,36 @@ approach with `case_<bool, Provider>` helpers. Only the selected case's provider
168170
allowing you to use `static_assert(false)` in default cases that should never be reached.
169171
Examples can be found [here](examples/examples_lazy_conditional.cpp).
170172

173+
174+
### `format_to_ostream`
175+
Provide an ostream `operator<<` overload for any type that is formattable with `std::format`.
176+
Does not override preexisting `operator<<` implementations.
177+
178+
The primary usage for this is for doctest tests, because doctest only supports output via `std::ostream` (not `std::format`).
179+
Note: for this to work it needs to be included **before** `<doctest/doctest.h>`.
180+
181+
182+
### `stdint`
183+
User defined literals for fixed size integers (e.g. `123_u64`).
184+
This is mainly useful for cross-platform applications where the common `123ul` is not always the same as `uint64_t{123}`.
185+
For instance, on macOS `uint64_t` is defined as `unsigned long long`, whereas on Linux it is defined as `unsigned long`.
186+
Even if both `unsigned long` and `unsigned long long` have the same size, they are still distinct types which can cause issues
187+
when a type is being deduced.
188+
189+
171190
### Further Examples
172191

173192
Compilable code examples can be found in [examples](./examples). The example build requires the cmake
174193
option `-DBUILD_EXAMPLES=ON` to be added.
175194

176195
## Requirements
177196

178-
A C++20 compatible compiler. Code was only tested on x86_64.
197+
A C++23 compatible compiler. Code was only tested on x86_64.
179198

180199
## Include it in your projects
181200
### Conan
182201
You can use it with [conan](https://conan.io/).
183-
To do so, you need to add `dice-template-library/1.20.0` to the `[requires]` section of your conan file.
202+
To do so, you need to add `dice-template-library/1.21.0` to the `[requires]` section of your conan file.
184203

185204
## Build and Run Tests and Examples
186205

examples/CMakeLists.txt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
set(CMAKE_CXX_STANDARD 20)
1+
set(CMAKE_CXX_STANDARD 23)
22
set(CMAKE_CXX_STANDARD_REQUIRED ON)
33
set(CMAKE_CXX_EXTENSIONS OFF)
44

@@ -162,4 +162,18 @@ add_executable(examples_lazy_conditional
162162
target_link_libraries(examples_lazy_conditional
163163
PRIVATE
164164
dice-template-library::dice-template-library
165-
)
165+
)
166+
167+
add_executable(example_format_to_ostream
168+
example_format_to_ostream.cpp)
169+
target_link_libraries(example_format_to_ostream
170+
PRIVATE
171+
dice-template-library::dice-template-library
172+
)
173+
174+
add_executable(example_stdint
175+
example_stdint.cpp)
176+
target_link_libraries(example_stdint
177+
PRIVATE
178+
dice-template-library::dice-template-library
179+
)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Include the overload that makes it ostreamable.
2+
#include <dice/template-library/format_to_ostream.hpp>
3+
4+
#include <format>
5+
#include <iostream>
6+
#include <sstream>
7+
#include <string>
8+
9+
// A type that has no std::ostream operator<< defined
10+
struct not_ostreamable {
11+
int value;
12+
};
13+
14+
template<>
15+
struct std::formatter<not_ostreamable> {
16+
template<typename Ctx>
17+
constexpr auto parse(Ctx &ctx) {
18+
return ctx.begin();
19+
}
20+
21+
template<typename Ctx>
22+
auto format(not_ostreamable const &nos, Ctx &ctx) const {
23+
// careful to pass `nos.value` instead of `nos` to the formatter to avoid infinite recursions.
24+
return std::format_to(ctx.out(), "{}", nos.value);
25+
}
26+
};
27+
28+
29+
int main() {
30+
not_ostreamable e{1};
31+
std::cout << e;
32+
}
33+

examples/example_stdint.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <dice/template-library/stdint.hpp>
2+
3+
#include <cassert>
4+
#include <cstdint>
5+
#include <type_traits>
6+
7+
int main() {
8+
using namespace dice::template_library::literals;
9+
10+
auto value = 123_u64;
11+
static_assert(std::is_same_v<decltype(value), uint64_t>);
12+
assert(value == 123);
13+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#ifndef DICE_TEMPLATELIBRARY_FORMAT_TO_OSTREAM
2+
#define DICE_TEMPLATELIBRARY_FORMAT_TO_OSTREAM
3+
4+
/*!
5+
* Note: This file does not use concepts/requires anywhere because their evaluation
6+
* causes an infinite loop (compiler error: "evaluation of constraint depends on itself").
7+
*
8+
* Old-school SFINAE does not have this issue.
9+
*/
10+
11+
#include <format>
12+
#include <iterator>
13+
#include <ostream>
14+
#include <string>
15+
#include <type_traits>
16+
17+
namespace dice::template_library {
18+
19+
/**
20+
* Detect if a type can be used with operator<< of an ostream.
21+
*
22+
* @tparam T type to check
23+
* @tparam Char char-type of the ostream
24+
* @tparam CharTraits char-traits-type of the ostream
25+
*/
26+
template<typename T, typename Char, typename CharTraits, typename = void>
27+
struct is_ostreamable : std::false_type {
28+
};
29+
30+
template<typename T, typename Char, typename CharTraits>
31+
struct is_ostreamable<T, Char, CharTraits, std::void_t<decltype(std::declval<std::basic_ostream<Char, CharTraits> &>() << std::declval<T const &>())>> : std::true_type {
32+
};
33+
34+
template<typename T, typename Char, typename CharTraits>
35+
inline constexpr bool is_ostreamable_v = is_ostreamable<T, Char, CharTraits>::value;
36+
37+
} // namespace dice::template_library
38+
39+
/**
40+
* An overload for ostream operator<< for any type that is formattable with std::format
41+
*
42+
* @tparam Char char-type of the ostream and the formatter
43+
* @tparam CharTraits char-traits-type of the ostream
44+
* @param stream ostream
45+
* @param value value to stream via std::formatter implementation
46+
* @return stream
47+
*/
48+
template<typename T, typename Char = char, typename CharTraits = std::char_traits<char>, typename = std::enable_if_t<std::formattable<T, Char> && !dice::template_library::is_ostreamable_v<T, Char, CharTraits>>>
49+
std::basic_ostream<Char, CharTraits> &operator<<(std::basic_ostream<Char, CharTraits> &stream, T const &value) {
50+
std::format_to(std::ostreambuf_iterator<Char, CharTraits>{stream}, "{}", value);
51+
return stream;
52+
}
53+
54+
#endif // DICE_TEMPLATELIBRARY_FORMAT_TO_OSTREAM

0 commit comments

Comments
 (0)