2.5 KiB
2.5 KiB
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.
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:
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");
|