elseif condition in macro

Oct 7, 2022 at 6:21pm
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 Oct 7, 2022 at 6:21pm
Oct 7, 2022 at 7:27pm
> #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
Oct 7, 2022 at 7:57pm
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.
Oct 8, 2022 at 9:31am
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 Oct 8, 2022 at 10:55am
Oct 8, 2022 at 12:53pm
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 ) ;
Oct 9, 2022 at 11:40am
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 Oct 9, 2022 at 11:50am
Oct 9, 2022 at 11:50am
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 Oct 9, 2022 at 11:51am
Oct 10, 2022 at 6:22am
> 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?
Oct 10, 2022 at 8:43am
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};

Oct 10, 2022 at 5:53pm
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 Oct 10, 2022 at 5:53pm
Oct 10, 2022 at 8:43pm
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
Oct 10, 2022 at 10:36pm
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.
Oct 11, 2022 at 12:52am
Supposedly the introduction of modules was done in part to get around these "include a header multiple times" problems.

Yeah, m'ok.
Oct 19, 2022 at 9:43pm
thanks for your answers.
Topic archived. No new replies allowed.