CodeMonkey
CodeMonkey

Reputation: 12434

Constructing define names using strings

I got some constant int values I would like to use, So I used #define.

The issue is that I got some define names like this:

#define a1  123
#define a2  6543
#define a3  12
...

Is there a way in the code to somehow iterate over them to construct their name with strings and then get the define value of that constructed strings? A pseudo code of what I mean:

for(int i =0 ; i < 100; i++)
{
   string name = "a" + i;
   func(GetDefineName(name)); // should call here every time to func with a1,a2 etc.
}

I'm used to C# so I got some problems getting used to c++. Is define really the most appropriate way to do that?

Upvotes: 2

Views: 1248

Answers (5)

Jarod42
Jarod42

Reputation: 217810

Prefer const variable over MACRO

constexpr auto a1 = 123;
constexpr auto a2 = 6543;
constexpr auto a3 = 12;

Then to iterate over them, no need of the name, just do

for (auto e : {a1, a2, a3}) {
    func(e);
}

You might want to create a variable for the list to avoid repetition if you iterate at several place.

Upvotes: 1

Another approach is to generate some C++ file containing what you want. So you'll need to set up your build for that purpose. You often use some build automation tool (such as GNU make, ninja, etc...) and you can configure it to generate some C++ file when needed (e.g. by adding a few lines in your Makefile, if you use make). The program generating some C++ code could be some script (e.g. in shell, awk, Python, Guile, ...), some specialized metaprogram (such as moc for Qt programs), some other preprocessor like GPP or m4, or your own other C++ program, etc... This kind of metaprogramming approach is routinely used with C++ and C since the previous century (look into Qt moc, bison, SWIG, ... for examples).

See also this answer to a related question (with C).

You would generate some header containing stuff like

#define a1  123
#define a2  6543
#define a3  12

(you don't want = in such #define-s)

or you might generate some enum like

enum number_en {
 a1= 123,
 a2= 6543,
 a3= 12,
};

Notice that generating C++ code could be a more efficient (since build-time) solution at runtime than other (e.g. std::map based) approaches.

Upvotes: 2

4386427
4386427

Reputation: 44329

Is there a way in the code to somehow iterate over them to construct their name with strings and then get the define value of that constructed strings?

No, there is no way to do that using defines.

You'll need to put the values into some container to be able to iterate the values.

If you just want to store the values, you can use a std::vector.

If you want to have both a name and a value, you can use std::map. Something like:

#include <iostream>
#include <string>
#include <map>

#define a0 42
#define a1 5
#define a2 15
#define a3 25

int main() {
    // Define the map
    std::map<std::string, int> m;

    // Intialize the map
    m["a0"] = a0;
    m["a1"] = a1;
    m["a2"] = a2;
    m["a3"] = a3;

    // Access map using name
    for(size_t i =0 ; i < m.size(); i++)
    {
        std::string name = "a" + std::to_string(i);
        std::cout << m[name] << std::endl;
    }

    // Iterate all map elements
    for (auto& x : m)
    {
        std::cout << x.first << ":" << x.second << std::endl;
    }
    return 0;
}

Upvotes: 2

Clonk
Clonk

Reputation: 2070

Macro are parsed by the preprocessor and are unknown to the processor (you can't use them in your code).

If you want to associate a name to a value, you can use a const map and constexpr expression :

constexpr std::string a1="a1";
constexpr std::string a2="a2";
constexpr std::string a3="a3";

const std::map<std::string, int> = {
    {a1, 123},
    {a2, 6543},
    {a3, 12} 
}

You need C++11 (or above) in order for this to work.

Upvotes: 1

Loebl
Loebl

Reputation: 1431

Lines starting with # are evaluated by the preprocessor - the compiler won't see them, only their effects. C++ code can therefore not interact with preprocessor variables, as they don't exist anymore when the code is compiled.

Constants can be defined that way, but C++ offers better approaches. For example they can be wrapped in namespaces to avoid name collisions.

//auto lets the compiler deduce the type for you
auto const my_var = 4.5; //double
auto const close_to_pi = 3.4f; //float
auto const the_answer = 42; //int
auto const kibibyte = 1024u; //unsigned int

To get more explanations about the type defining suffixes have a look at integer literals and floating point literals. You might also want to read up on constexpr later when you are more comfortable with C++ to explore compile time constant expressions.

Upvotes: 3

Related Questions