I made a class for an arduino program. Inside the class I would like to toss a compiler error if a wrong pin number is passed as an argument.
class AnalogOutput : public AnalogBlock
{
public:
AnalogOutput( uint8_t _pin ) : pin( _pin )
{
static_assert
( pin == 3
|| pin == 5
|| pin == 6
|| pin == 9
|| pin == 10
|| pin == 11 , "INVALID PWM PIN USED"
) ;
}
void run()
{
if( IN2 != prevIn )
{ prevIn = IN2 ; // if incomming change, update PWM level
analogWrite( pin, IN2) ;
}
}
private:
const uint8_t pin ;
uint8_t prevIn ;
} ;
The constructor is only called with compile-time constants.
static ServoMotor M1 = ServoMotor( 3 ) ; // 3 is the pin number
Yet I get me this compiler error
error: non-constant condition for static assertion
static_assert (
^~~~~~~~~~~~~
error: use of 'this' in a constant expression
I looked here but it did not make me wizer. It is the first time that I am trying to use static_assert()
.
First question: what I am trying to do, can that be done in the first place? Second question: providing that the previous answer is 'yes' how can it be done?
CodePudding user response:
static_assert
is for compile-time constants only, thus, because you try to run something in the context of object construction (hence, runtime), the compiler refuses to generate code.
An alternative solution would be to use a template
d class
like such:
template<uint8_t pin>
class AnalogOutput
{
static_assert
( pin == 3
|| pin == 5
|| pin == 6
|| pin == 9
|| pin == 10
|| pin == 11 , "INVALID PWM PIN USED"
) ;
//blablabla
};
Though I remember having bad times with template
in Arduino due to bugs in their compiler. It was a few years ago, but still, use at your own risks.
CodePudding user response:
Instead of taking an uint8_t
, take an auto and pass an std::integral_constant<uint8_t, value>()
, where value
is the value you'd like to pass (e.g. 3
). It can be checked compile-time and can be converted to the underlying integral type, i.e., uint8_t
.
CodePudding user response:
A way without using any templates, is to make a consteval
function that only returns the constructed object if the condition is met. If the condition was false, it returns nothing and therefore the compiler will throw an error:
#include <cstdint>
struct ServoMotor {
constexpr ServoMotor(uint8_t pin) {}
};
constexpr bool valid_pin(uint8_t pin) {
return (pin == 3 || pin == 5 || pin == 6 ||
pin == 9 || pin == 10 || pin == 11);
}
consteval auto make_motor(uint8_t pin) {
if (valid_pin(pin)) {
return ServoMotor(pin);
}
}
int main() {
auto m3 = make_motor(3);
auto m4 = make_motor(4);
}
the line on m3
works as expected, but there is an error C7595
on the m4
line, since 4 is not a valid pin.
Try it out here.