I want to write for ARM 32-bit microcontroller and I want to use modern C++ for education. My goals is: readable code, configurable in compile-time and help compiler to generate maximum optimizations for size and speed. What language tools should I use to archive my goals? I write some code and static assertions does not work... Please help me to fix this code (add assertions and no overhead).
#include <initializer_list>
#include <vector>
typedef uint port_type;
typedef uint pin_type;
class Pin {
private:
const port_type _port;
const pin_type _pin;
public:
Pin(const port_type port, const pin_type pin) :
_port(port), _pin(pin) {
}
};
class Actuator {
private:
const Pin _enable_pin;
const Pin _dir_pin;
const Pin _step_pin;
public:
Actuator(const Pin enable_pin, const Pin dir_pin, const Pin step_pin) :
_enable_pin(enable_pin), _dir_pin(dir_pin), _step_pin(step_pin) {
}
};
class Machine {
private:
const std::vector<Actuator> _actuators;
public:
Machine(const std::initializer_list<Actuator> actuators) :
_actuators(actuators) {
/*check: all actuators _enable_pin ports are same*/
/*check: all actuators _dir_pin ports are same*/
/*check: all actuators _step_pin ports are same*/
/*check: all port/pin pairs are unique*/
}
};
int main() {
/*example: good sequence*/
Actuator act1(Pin(1, 1), Pin(1, 2), Pin(1, 3));
Actuator act2(Pin(1, 4), Pin(1, 5), Pin(1, 6));
Machine machine1( { act1, act2 });
/*example: bad sequence*/
Actuator act3(Pin(2, 1), Pin(2, 2), Pin(2, 2)); // NOK! Pin(2,2) already used!
Actuator act4(Pin(2, 1), Pin(2, 3), Pin(2, 4)); // NOK! Pin(2,1) already used in act3!
Machine machine2( { act3, act4 });
}
Using a lot of constexpr
, std::array
instead of std::vector
and defining Machine
as a template class (whose parameter is the dimension of the std::array
), you can transform the constructor of Machine
in a constexpr
method that throw an exception at runtime or, when the object Machine
is defined constexpr
, compiletime.
The following example (unfortunately C++14 but not C++11) intercept, compile-time, that there are two equals Pin
s in act3
#include <array>
#include <stdexcept>
#include <initializer_list>
typedef std::size_t port_type;
typedef std::size_t pin_type;
class Pin
{
private:
port_type const _port;
pin_type const _pin;
public:
constexpr Pin (port_type const port, pin_type const pin)
: _port{port}, _pin{pin}
{ }
friend constexpr bool operator== (Pin const & p1, Pin const & p2)
{ return (p1._port == p2._port) && (p1._pin == p2._pin); }
};
class Actuator
{
private:
Pin const _enable_pin;
Pin const _dir_pin;
Pin const _step_pin;
public:
constexpr Actuator (Pin const ep, Pin const dp, Pin const sp)
: _enable_pin{ep}, _dir_pin{dp}, _step_pin{sp}
{ }
constexpr bool checkColl () const
{ return (_enable_pin == _dir_pin) || (_enable_pin == _step_pin)
|| (_dir_pin == _step_pin); }
};
template <std::size_t N>
class Machine
{
private:
std::array<Actuator, N> const _actuators;
public:
template <typename ... Args>
constexpr Machine (Args const & ... actuators)
: _actuators{ { actuators ... } }
{
static_assert(sizeof...(Args) == N, "!");
for ( auto ui = 0U ; ui < N ; ++ui )
{
if ( _actuators[ui].checkColl() )
throw std::logic_error("port collision");
// other checks here
}
}
};
int main()
{
constexpr Actuator act1 { Pin{ 1, 1 }, Pin{ 1, 2 }, Pin{ 1, 3 } };
constexpr Actuator act2 { Pin{ 1, 4 }, Pin{ 1, 5 }, Pin{ 1, 6 } };
constexpr Machine<2U> machine1 { act1, act2 };
constexpr Actuator act3 { Pin{ 2, 1 }, Pin{ 2, 2 }, Pin{ 2, 2 } };
constexpr Actuator act4 { Pin{ 2, 1 }, Pin{ 2, 3 }, Pin{ 2, 4 } };
constexpr Machine<2U> machine2 { act3, act4 }; // compilation error
}
You can add the other checks.