106 lines
2.5 KiB
Markdown
106 lines
2.5 KiB
Markdown
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");
|
||
|
|
||
```
|