elseif condition in macro

anyone knows why I am not getting the _dim and _nnodeLtc correctly from the following piece of code?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#pragma once
#ifndef _INCLUDES_H_
#define _INCLUDES_H_

#define D2Q9

#ifndef D1Q3

constexpr int _dim{ 2 };
constexpr int _nNodeLtc{ 3 };


#elif D2Q9
constexpr int _dim{ 3 };
constexpr int _nNodeLtc{ 9 };

#elif D3Q19

constexpr int _dim{ 3 };
constexpr int _nNodeLtc{ 19 };

#elif D3Q27

constexpr int _dim{ 3 };
constexpr int _nNodeLtc{ 27 };

#endif 

#endif 
Last edited on
> #ifndef D1Q3

Perhaps this one should also be
#if D1Q3

It might be better to write
1
2
3
#if defined(D1Q3)

#elif defined(D2Q9) 

etc
not a problem but I am a big fan of factoring unless you think your conditions may change drastically later.
if this is pretty much what its going to be, just say

#if condition
dim is 2
#else
dim is 3 //don't repeat this many times.

followed by a section for conditions for the other one.
Try this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#define D2Q9

#if defined D1Q3
    constexpr int _dim{ 2 };
    constexpr int _nNodeLtc{ 3 };
#elif defined D2Q9
    constexpr int _dim{ 3 };
    constexpr int _nNodeLtc{ 9 };
#elif defined D3Q19
    constexpr int _dim{ 3 };
    constexpr int _nNodeLtc{ 19 };
#elif defined D3Q27
    constexpr int _dim{ 3 };
    constexpr int _nNodeLtc{ 27 };
#else
    #pragma message("NOT DEFINED");
#endif 

Last edited on
Avoid identifiers that begins with an underscore (like _dim and _nnodeLtc) in the global namespace.

In addition, some identifiers are reserved for use by C++ implementations and shall not be used otherwise; no diagnostic is required.

- Each identifier that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.

- Each identifier that begins with an underscore is reserved to the implementation for use as a name in the global namespace.

https://eel.is/c++draft/lex.name#3


As a rule of thumb, if you can find a clean and manageable way to do something without the preprocessor, then you should do it that way.
- Boost Preprocessor Library https://www.boost.org/doc/libs/1_80_0/libs/preprocessor/doc/index.html


This may be an alternative:

1
2
3
4
5
6
7
8
9
10
11
enum dq_t { D1Q3 = 103, D2Q9 = 209, D3Q19 = 319, D3Q27 = 327 };

constexpr dq_t default_dq_t = D2Q9 ; // #define D2Q9

consteval int eval_dim( dq_t dq = default_dq_t ) { return dq / 100 ; }
consteval int eval_n_node_ltc( dq_t dq = default_dq_t ) { return dq % 100 ; }

constexpr int dim_ = eval_dim() ;
constexpr int n_node_ltc_ = eval_n_node_ltc() ;

static_assert( default_dq_t == D2Q9 && dim_ == 2 && n_node_ltc_ == 9 ) ;
Shouldn't D1Q3 be 203 and D2Q9 be 309 from the original post?

Another way using lambdas could be:

1
2
3
4
5
6
enum dq_t {D1Q3 = 203, D2Q9 = 309, D3Q19 = 319, D3Q27 = 327 };

constexpr int dim_ { [](dq_t d = D1Q3) {return d / 100; }(D2Q9) };
constexpr int nNodeLtc_ { [](dq_t d = D1Q3) {return d % 100; }(D2Q9) };

static_assert(dim_ == 3 && nNodeLtc_ == 9);


Last edited on
This can done using structured binding - but then dim_ and nNodeLtc_ are not constexpr - just const - as constexpr can't be used with structured binding

1
2
3
enum dq_t {D1Q3 = 203, D2Q9 = 309, D3Q19 = 319, D3Q27 = 327 };

const auto [dim_, nNodeLtc_] {[](dq_t d = D1Q3) {return std::pair { d / 100, d % 100 }; }(D2Q9)};


Last edited on
> Another way using lambdas could be:
> constexpr int dim_ { [](dq_t d = D1Q3) {return d / 100; }(D2Q9) };

Why? constexpr int dim_ = D2Q9 / 100 ; // isn't this a lot cleaner?
Yeah - I realised that later. I was just playing with the constexpr code above... :)

1
2
3
4
5
6
enum dq_t {D1Q3 = 203, D2Q9 = 309, D3Q19 = 319, D3Q27 = 327 };

constexpr auto ToUse {D2Q9};    // Set as needed

constexpr int dim_ {ToUse / 100};
constexpr int nNodeLtc_ {ToUse % 100};

actually, I will go out on a limb an say that it is getting less readable as you move more and more into compacted modern forms.
Clever, yes. Readable to the intern you just hired? Nope. Do I do this stuff too? Yes.
Last edited on
And let's not get too far away from the idea that using #pragma once is not standard C++. It is implementation defined.

It is recognized by most current compilers, but not guaranteed by the C++ standard.
https://stackoverflow.com/questions/23696115/is-pragma-once-part-of-the-c11-standard

There is the potential for a rather nasty bug when using #pragma once :
Unlike header guards, this pragma makes it impossible to erroneously use the same macro name in more than one file. On the other hand, since with #pragma once files are excluded based on their filesystem-level identity, this can't protect against including a header twice if it exists in more than one location in a project.

https://en.cppreference.com/w/cpp/preprocessor/impl
On the other hand, since with #pragma once files are excluded based on their filesystem-level identity, this can't protect against including a header twice if it exists in more than one location in a project.
On the other other hand, if you're doing something silly like bringing in the same dependency from multiple places willy-nilly, or having symlinks in your build tree, you'll likely run into secondary problems either way, and the fact that your project doesn't build is relatively benign.
Supposedly the introduction of modules was done in part to get around these "include a header multiple times" problems.

Yeah, m'ok.
thanks for your answers.
Topic archived. No new replies allowed.