Can a macro be assigned an enum in a library?

Hello,

I am trying to create a way in this library, to be able to pass an option in the library's instantiation using simple terms. And instead of using a primitive data type, I want to use an enum which in this situation would be a perfect option.

I created a model library for simplicity to show what it is i am TRYING to do. I use CLion as my IDE and it doesn't seem to have a problem with what I'm doing, but when I compile the sketch, the compiler throws an error:

error: expected primary-expression before '.'

and it references the macro declaration.

Anyways, here is the example library:

header:

#ifndef Library_h
#define Library_h

#define OPTION1 options.O1
#define OPTION2 options.O2
#define OPTION3 options.O3

class Library {

    enum options {
        O1, O2, O3
    };

public:
    Library(unsigned long time, char color);
    Library(unsigned long time, char color, options option);

private:
    unsigned long timeValue = 0;
    char mainColor;
    options userOption;

};
#endif

code:

#include "library.h"

Library::Library(unsigned long time, char color) {
    timeValue = time;
    mainColor = color;
}

Library::Library(unsigned long time, char color, options option) {
    timeValue = time;
    mainColor = color;
    userOption = option;
}

And this is how the sketch would look:

#include <library.h>

Library go(1000, 8, OPTION2);

setup() {
}

loop() {
}

Is it possible to do something like this in C++?

Thank you

Hello

You can move the enum outside of the class so options will be available in the global scope

Then you must use :: not . :
#define OPTION1 options::O1

The enum must be public in the class. Also, use:

#define OPTION1 Library::O1

But, why not use:

enum options {
   OPTION1, OPTION2, OPTION3
};

Then:

Library go(1000, 8, Library::OPTION2);

That is the weirdest way to use an enum I've ever seen. Normally you would just:

    enum options {
        OPTION1, OPTION2, OPTION3
    };
class Library {...
#define OPTION1 options.O1
#define OPTION2 options.O2
#define OPTION3 options.O3

That is not how you refer to the members of an enum. Are you confusing it with the syntax used to access the members of a struct ?

For simplicity for the user of the library ... its easier to just pass in a single word as the option.

If the enum is defined in the class header, you can use it the way you describe, in the primary sketch. Or in the class, and using the scope resolution operator, as in reply #4.

Thank you, that worked well. It compiles now.

:slight_smile:

But I agree that it isn't really the proper way to use an enum, it's better to do it like in reply 4 as to avoid possible names collisions

You did mention simplicity...

Not sure what you mean exactly by name collisions, but if you're referring to the name of the macro itself, I suppose it could happen if the user of the library was using another library with the same macro name ... but that would be an issue whether or not I assigned an enum value to the macro or not, right?

Or are you referring to the name of the enum as a possible 'name collision'?

If the user or another library have a variable/function/macro/whatever, named OPTION1, in most cases there will be an error. For example if the user declare a variable int OPTION1 = 123; after including your library, then that name will be replaced by the content of your macro, it will become int options::O1 = 123; which is not good

But if you use

class Library {
  public :
    enum options {
      OPTION1, OPTION2, OPTION3
    };
  ...
}

...

Library go(1000, 8, Library::OPTION1);

It will compile

OK, so then I don't understand how to structure the header file so that this problem can be avoided, because we have given the macro this definition:

#define OPTION1 options::OPTION1

And I can't see how passing in Library:OPTION1 into the class constructor is any different that just passing in OPTION1 ... or am I missing something?

See this example : xXmR9u - Online C++ Compiler & Debugging Tool - Ideone.com

Using Library:: in front is not a problem, that's how it should be done, even if it's less beginner-friendly, it's good practice and avoids problems

OK, I see where you're going with this in your example, so I change the header and .cpp file and then made a quick sketch:

library.h:

#ifndef Library_h
#define Library_h

class Library {


public:
    enum options {
        OPTION1, OPTION2, OPTION3
    };

    Library(unsigned long time, char color, options option);

private:
    unsigned long timeValue = 0;
    char mainColor;
    options userOption;
};
#endif

library.cpp:

#include "library.h"

Library::Library(unsigned long time, char color, options option) {
    timeValue = time;
    mainColor = color;
    userOption = option;
}

Sketch:

#include <library.h>

Library go(100,4,Library::OPTION2);

void setup() {

}

void loop() {

}

I didn't see in the example you made, where there was any definition for Library::OPTION1

And when I try to compile the sketch, this is what happens:

/var/folders/vb/rq_5f8jj11v06z8yq8pg3hdh0000gn/T//ccFt5nhS.ltrans0.ltrans.o: In function `__static_initialization_and_destruction_0':
/Users/michael/Arduino/test/test.ino:3: undefined reference to `Library::Library(unsigned long, char, Library::options)'
collect2: error: ld returned 1 exit status
exit status 1
Error compiling for board Arduino Nano.

That code compiles for me.

Don't hide simple syntax like that behind macros. It hides the structure of the code from both humans and tools.
Library::Option1 is simple, correct, and unambiguous.
Any decent IDE will automatically prepend Library:: if you enable autocomplete, and any C++ programmer should be familiar with that syntax. IMO, you're not doing your users a favor by introducing nonstandard macros.