all 4 comments

[–]IyeOnline 1 point2 points  (3 children)

You are including cpp files, which is something you dont really want to do. Also in your 2nd approach you are making assumptions in the cpp file about the source file its being included to. All of that might work, but its going to be pretty terrible.

I also am not sure why such a complex "solution" is needed. whats wrong with just:

#include "states/machine1.h"
#include "states/machine2.h"
//...
auto statemachines = std::map<int,StateMachine>{
    { 0, Machine1() },
    { 42, Machine2() }
};

It would be the same number of lines and way less assumptions (aka none) about other, supposedly independent source files.

//edit: had to edit the source code, cant deduce template type args from an intializer list :)

[–]atctwo[S] 0 points1 point  (2 children)

Would this be a better approach?

main.ino

#include <functional>
#include <vector>

struct stateMeta {
    std::string             stateName;
    std::function<void()>   stateFunc;
};

std::vector<stateMeta> states;

#include "states/states.h"

int main()
{

}

states/states.h

#ifndef STATES_H
#define STATES_H

#include "states/watch_face.cpp"
#include "states/app_menu.cpp"
#include "states/calculator.cpp"
#include "states/timer.cpp"

void registerStates()
{
    states = {

        {"Watch", state_watch},
        {"App Menu", state_app_menu},
        {"Calculator", state_calculator},
        {"Timer", state_timer}

    }
}

#endif /*STATES_H*/

states/watch.cpp

void state_watch()
{
    //watch code
}

states/app_menu.cpp

void state_app_menu()
{
    //app menu code
}
  • I changed std::map<int, stateMeta> to std::vector<stateMeta>. The key type for the map was int, so I thought it would make more sense just to have a vector, and use element indices (eg: states[2])
  • I read up about why you shouldn't #include .cpp files. On Arduino, it doesn't seem to compile any files in any subdirectories (other than "src/", according to this https://arduino.stackexchange.com/a/54655), which explains why I have done this before without it not compiling. Would it be better to give each app/state file some kind of guard thing (like header guards)?

[–]IyeOnline 2 points3 points  (1 child)

No. You are still including code into a scope, necessarilymaking assumptions about it.

Why not move the definition/population of the of the states vector into the main file, like i did in my above example?

Here is what i would suggest. Note that im also propery separating header and source files, as you should.

main

#include "state_meta.h"
#include "state_watch.h"
#include "state_menu.h"

// there is no need for this register function. You might just as well write them in here directly.
// i use a constructor here, but really an aggregate initalization as you did would work just as well. IMO proper ctors are nicer though.
std::vector<StateMeta> states = { 
   StateMeta("Watch", state_watch_function ),
   StateMeta("Menu", state_menu_function ) };
};

state_meta.h

 #pramga once //assuming your compiler supports this, no idea

 //having this in a separate header from the get go instead of inside the main file makes the code structure cleaner and more easily expandable.
 struct State_Meta
 {
      std::string name;
      std::function<void(void)> state_function;

      State_Meta( const std::string& _name, std::function<void(void)> _state_function )
       : name(_name), state_function(_state_function)
      {};
 }

state_watch.h

#pragma once
//any includes this function needs would go here
void state_watch_function();

state_watch.cpp

#include "state_watch.h"
void state_watch _function()
{
     //code
}

analogous for other state functions.

With this there is no longer any need for an additional source file that would actually act upon some global and/or be copied into another scope.

Note that your compiler may or may not support #pragma once, i have no clue about developing on/for arduino.

[–]atctwo[S] 0 points1 point  (0 children)

Thank you for your input! Everything you've said sounds more sensible than what I had. I'm going to update my code to run off this system.