Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ if(ESP_PLATFORM)
endif()

project(thermo
VERSION 2.0.0
VERSION 2.1.0
DESCRIPTION "Type-safe temperature handling library modeled after std::chrono"
HOMEPAGE_URL "https://github.com/cleishm/thermo-cpp"
LANGUAGES CXX
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,23 @@ using namespace thermo_literals;
293_k // kelvin(293)
68_f // fahrenheit(68)

// Negative absolute temperatures (unary minus on the literal)
-123_dc // decicelsius(-123) = -12.3°C
-40_f // fahrenheit(-40)
// -25_k // ill-formed: negating a Kelvin temperature falls below absolute zero

// Temperature deltas
5_Δc // delta_celsius(5)
5000_Δmc // delta_millicelsius(5000)
9_Δf // delta_fahrenheit(9) = delta_celsius(5)
```

Unary minus is available on relative scales (Celsius, Fahrenheit) so that
negative literals like `-123_dc` work — the sign is applied to the value the
literal produces, i.e. `-(123_dc)`. It is deliberately *not* available on the
absolute Kelvin scale, where a negated temperature would fall below absolute
zero; `-25_k` is a compile error. Deltas are negatable on every scale.

## Conversion Rules

Conversions follow the same philosophy as `std::chrono`:
Expand Down
2 changes: 1 addition & 1 deletion docs/Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "thermo"
PROJECT_NUMBER = "2.0.0"
PROJECT_NUMBER = "2.1.0"
PROJECT_BRIEF = "Type-safe temperature handling library modeled after std::chrono"
PROJECT_LOGO =
OUTPUT_DIRECTORY = .
Expand Down
2 changes: 1 addition & 1 deletion idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: "2.0.0"
version: "2.1.0"
description: "Type-safe temperature handling library modeled after std::chrono"
url: "https://github.com/cleishm/thermo-cpp"
repository: "https://github.com/cleishm/thermo-cpp.git"
Expand Down
24 changes: 24 additions & 0 deletions include/thermo/thermo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,17 @@ struct fahrenheit_scale {
using degree = std::ratio<5, 9>;
static constexpr const char* suffix = "°F";
};

/**
* @brief True when a scale's zero point is not absolute zero.
*
* Negating an absolute temperature only makes sense on a "relative" scale
* (e.g. Celsius, Fahrenheit), where the zero point sits above absolute zero.
* On an absolute scale (Kelvin, offset == 0) a negated temperature always
* falls below absolute zero, so unary minus is disabled there.
*/
template<typename Scale>
inline constexpr bool _is_relative_scale = std::ratio_not_equal_v<typename Scale::offset, std::ratio<0>>;
/** @endcond */

template<typename Scale, typename Delta = delta<int64_t>>
Expand Down Expand Up @@ -729,6 +740,19 @@ class temperature {

constexpr temperature operator--(int) { return temperature(_d--); }

/**
* @brief Negates the temperature (e.g. to write @c -123_dc as @c -(123_dc)).
*
* Only available on relative scales such as Celsius and Fahrenheit; on an
* absolute scale (Kelvin) negation would fall below absolute zero and is a
* compile error. See @ref _is_relative_scale.
*/
constexpr temperature operator-() const
requires _is_relative_scale<Scale>
{
return temperature(-_d);
}

template<typename Rep2, typename Precision2>
constexpr temperature& operator+=(const delta<Rep2, Precision2>& d) {
_d += d;
Expand Down
30 changes: 30 additions & 0 deletions tests/thermo_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,36 @@ TEST_CASE("delta literals", "[thermo][literals]") {
REQUIRE((9000_Δmf).count() == 9000);
}

// =============================================================================
// Negation (enables negative literals, e.g. -123_dc == -(123_dc))
// =============================================================================

template<typename T>
concept has_unary_minus = requires(T t) { -t; };

// Available on relative scales (zero above absolute zero)...
static_assert(has_unary_minus<celsius>);
static_assert(has_unary_minus<decicelsius>);
static_assert(has_unary_minus<fahrenheit>);
// ...but not on the absolute scale, where a negated value is below absolute zero.
static_assert(!has_unary_minus<kelvin>);
static_assert(!has_unary_minus<decikelvin>);
static_assert(!has_unary_minus<millikelvin>);

// Compile-time tests
static_assert((-123_dc).count() == -123);
static_assert((-40_f).count() == -40);
static_assert((-20_c).count() == -20);
static_assert(-(-5_c) == 5_c);

// Runtime tests
TEST_CASE("temperature negation", "[thermo][temperature]") {
REQUIRE((-123_dc).count() == -123);
REQUIRE((-40_f).count() == -40);
REQUIRE((-20_c).count() == -20);
REQUIRE((-(-5_c)).count() == 5);
}

// =============================================================================
// String formatting
// =============================================================================
Expand Down
2 changes: 1 addition & 1 deletion vcpkg-port/vcpkg.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cleishm-thermo-cpp",
"version": "2.0.0",
"version": "2.1.0",
"description": "Type-safe temperature handling library modeled after std::chrono",
"homepage": "https://github.com/cleishm/thermo-cpp",
"license": "MIT",
Expand Down
Loading