gists/cpp/compile-time-settings-check.md

106 lines
2.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

It is sometimes useful to be able to verify that certain settings are valid at
compile time. An easy approach to do this is to pass the settings as non-type
template arguments and use `static_assert()`.
The code snippet below demonstrates an approach which doesn't require templates
and cleanly separates the verification logic from the rest of the code.
```cpp
namespace i2c {
//
//
// Driver Settings
//
//
struct Settings {
int sclPin = 0;
int sdaPin = 0;
std::size_t freqHz = 1'000'000;
};
namespace detail {
struct SettingsChecker {
public:
consteval SettingsChecker(Settings settings) : mSettings{settings} {
bool validPinSettings =
(settings.sclPin == 1 && settings.sdaPin == 2) ||
(settings.sclPin == 3 && settings.sdaPin == 4);
bool validFreqSettings =
(settings.freqHz < 10'000'000) && (settings.freqHz > 100);
// Exceptions thrown in consteval functions lead to compile time errors
if (!validPinSettings) throw std::logic_error("Wrong I2C pin settings");
if (!validFreqSettings)
throw std::logic_error("Wrong I2C frequency settings");
}
constexpr operator Settings() const {
return mSettings;
}
private:
Settings mSettings;
};
} // namespace detail
//
//
// Driver class
//
//
class Driver {
public:
Driver(detail::SettingsChecker settings) : mSettings(settings) {
}
private:
Settings mSettings;
};
} // namespace i2c
//
//
// Usage
//
//
int main() {
constexpr i2c::Settings settings1 = {
.sclPin = 1, .sdaPin = 2, .freqHz = 1'000'000};
i2c::Driver driver1{settings1}; // Compiles
constexpr i2c::Settings settings2 = {
.sclPin = 1, .sdaPin = 4, .freqHz = 1'000'000};
i2c::Driver driver2{settings2}; // Compile time error
}
```
Compiling the above code leads to the following error:
```bash
compile-time-settings-check.cpp: In function int main():
compile-time-settings-check.cpp:88:34: error: call to consteval function i2c::detail::SettingsChecker(settings2) is not a constant expression
88 | i2c::Driver driver2{settings2}; // Compile-time error
| ^
compile-time-settings-check.cpp:88:34: in constexpr expansion of i2c::detail::SettingsChecker(settings2)
compile-time-settings-check.cpp:36:32: error: expression <throw-expression> is not a constant expression
36 | if (!validPinSettings) throw std::logic_error("Wrong I2C pin settings");
|
```