Member function [c++] definition not found by VS2015 due to #define - c++

Have a #define which is called within a member function. By this #define the member-function definition isn't found by the VS2015 environment at the declaration level. The project compiles and runs just fine so no problem there.
This does however, break the functionality of VS2015 to jump between the declaration and definition.
It can be solved by writing the #define within the source, but can this be solved without removing the #define?
File: cFoo.h
class cFoo
{
public:
int Bits;
void Member();
}
File: cFoo.cpp
#include "cFoo.h"
#define SWITCH( x ) for ( int bit = 1; x >= bit; bit *= 2) if (x & bit) switch (bit)
void cFoo::Member()
{
SWITCH( Bits )
{
case 1: break;
case 2: break;
default: break;
}
}

I would disadvice to use such constructs. It is rather counterintuitive and difficult to understand.
Possible problems/difficulties:
switch case with breaks suggests that only one case is executed, but your macro logic hides the loop.
the default case is executed multiple times depending on the highest populated bit.
using signed int as bit set -> use unsigned - its less prone to implementation defined behavior
it is possibly slow because of loop (I do not know if the compiler is able to unroll and optimize it)
its called SWITCH_BITS which suggests that bit numbers are expected, but cases have to be powers of two.
Your whole statement is not more compact than a simple if sequence.
if(bits & 1 ){
}
if(bits & 1024){
}
but you maybe want to test to bit numbers:
inline bool isBitSet(u32 i_bitset, u32 i_bit){ return i_bitset & (1 << i_bit);}
if(isBitSet(bits, 0){
}
if(isBitSet(bits, 10){
}

You can try doing this by completing the switch statement within the #define - macro:
Foo.h
#ifndef FOO_H
#define FOO_H
#ifndef SWITCH
#define SWITCH(x) \
do { \
for ( int bit = 1; (x) >= bit; bit *=2 ) { \
if ( (x) & bit ) { \
switch( bit ) { \
case 0: break; \
case 1: break; \
default: break; \
} \
} \
} \
} while(0)
#endif
class Foo {
public:
int Bits;
void Member();
};
#endif // !FOO_H
Foo.cpp
#include "Foo.h"
void Foo::Member() {
SWITCH( this->Bits );
}
When I was trying the #define or macro as you had it, Foo::Member()
was not being defined by intellisense...
However even with it not being defined I was able to build, compile and run it like this:
#ifndef SWITCH_A
#define SWITCH_A(x) \
for ( int bit = 1; (x) >= bit; bit *= 2 ) \
if ( (x) & bit ) \
switch (bit)
#endif
For some reason; MS Visual Studio was being very picky with it; meaning that I was having a hard time getting it to compile; it was even complaining about the "spacing" giving me compiler errors of missing { or ; need before... etc. Once I got all the spacing down properly it did eventually compile & run, but intellisense was not able to see that Foo::Member() was defined. When I tried it in the original manner that I've shown above; intellisense had no problem seeing that Foo::Member() was defined. Don't know if it's a pre-compiler bug, MS Visual Studio bug etc.; Just hope that this helps you.

Related

C++ Macro expanding in ordinal numbers

I have a code that compiles on various platforms having different features on or off (each represented by a specific define) and I am scratching my head on how to do the following switch (int) statement that would keep "case (number):" ordered and continuous.
int funcParam;
switch(funcParam)
{
case 0: break;
case 1:break;
#ifdef FEATURE_1
case 2: break;
#endif // FEATURE_1
case 3: break; // <<== problem here: 3 follows 1 if FEATURE_1 is not defined
#ifdef FEATURE_2
case 4: break; <<== problem here: 4 follows 2 if FEATURE_1 is not defined
#endif // FEATURE_2
#ifdef FEATURE_3
case 5: break; <<== problem here: 5 follows 2 or 3 or 4 depending on features
#endif // FEATURE_3
}
Each case block of code is a block of 10 or so lines, I guess this is irrelevant, however the perfect solution to have would be to find a way to emit code like:
case NEXTNUM:
that would expand to a next ordinal number with each expansion of a macro NEXTNUM.
Not having an idea on how could it possibly be written.
Please keep in mind that I am using quite old compiler (C++98, may consider C++03).
EDIT:
Found eventually a very similar question here:
Auto-incrementing macro expansion
which boils down to a very simple solution that is using enums instead of just plain numbers.
Thanks, Radek
Create variables equal 0 and 1 depending on if the feature is enabled. Add these variables to cases after the feature case.
int main() {
int funcParam;
const int add_feature_1 =
#ifdef FEATURE_1
1
#else
0
#endif
;
const int add_feature_2 =
#ifdef FEATURE_2
1
#else
0
#endif
;
const int add_feature_3 =
#ifdef FEATURE_3
1
#else
0
#endif
;
switch(funcParam) {
case 0: break;
case 1: break;
#ifdef FEATURE_1
case 2: break;
#endif
case 2 + add_feature_1: break;
#ifdef FEATURE_2
case 3 + add_feature_1: break;
#endif // FEATURE_2
#ifdef FEATURE_3
case 3 + add_feature_1 + add_feature_2: break;
#endif // FEATURE_3
}
}
Consider refactoring your code, so that FEATURE_X has to be defined (which I consider better) and instead define FEATURE_X to number 0 or 1. Then you could:
#define FEATURE_1 0
#define FEATURE_2 1
#define FEATURE_3 0
int main() {
int funcParam;
switch(funcParam) {
case 0: break;
case 1: break;
#if FEATURE_1
case 2: break;
#endif
case 2 + FEATURE_1: break;
#if FEATURE_2
case 3 + FEATURE_1: break;
#endif // FEATURE_2
#if FEATURE_3
case 3 + FEATURE_1 + FEATURE_2: break;
#endif // FEATURE_3
}
}
Or similar combinations, you should get the idea.
instead of case 0, case 1… and so on, use values from an enum; these are also compile-time constants, and thus, legal as case values.
You can insert the same #ifdef feature checks into the enum definition, then the enum options are still continuously labeled.
Rule of thumb though:
you're not making anything prettier that way. Honestly, having a feature enabled or not should probably not change the values functions exchange – that's just ugly and a recipe for debugging disaster. So, I question your motivation!
a case costs nearly nothing. Instead or removing these cases, you should probably think about what the right operation is when that case is triggered. A warning? A system shutdown?
The fact that you're not using an enum in switch/case is a really um, bad sign, and you relying on cases still being contiguously numbered is actively worrying. Using magic numerical constants is bad enough style on its own – making them have different meanings on different feature sets screams "architectural mistakes have been made". I'd duly replace all my magic numeric values with entries from an enum. You will be happier afterwards.
Lastly: uff. C++98. C++03 is 20 years old. It's an important bug-fix release that basically broke nothing. You really should not hesitate a second to use it.

How to get a boolean indicating if a macro is defined or not?

My code is configurable with define macros. To get the value in the code, I'm doing this:
#ifdef CONFIG_X
static constexpr bool x = true;
#else
static constexpr bool x = false;
#endif
But this is quickly becoming very ugly in the code with several configuration variables...
Another solution I found is simply to cut the code in two:
#ifdef CONFIG_X
#define CONFIG_X_BOOL true
#else
#define CONFIG_X_BOOL false
#endif
static constexpr bool x = CONFIG_X_BOOL;
This is a bit better, but not really nice either.
Is there a nice way to have a boolean or a 1 or 0 if a macro is defined ?
This IS possible, but only in the limited case where you are looking for empty defines (as is often the case with compilation flags) or where you know the range of ways a flag will be defined, such as with a 0 or 1.
Here is working code:
#include <iostream>
// Define two genetic macros
#define SECOND_ARG(A,B,...) B
#define CONCAT2(A,B) A ## B
// If a macro is detected, add an arg, so the second one will be 1.
#define DETECT_EXIST_TRUE ~,1
// DETECT_EXIST merely concats a converted macro to the end of DETECT_EXIST_TRUE.
// If empty, DETECT_EXIST_TRUE converts fine. If not 0 remains second argument.
#define DETECT_EXIST(X) DETECT_EXIST_IMPL(CONCAT2(DETECT_EXIST_TRUE,X), 0, ~)
#define DETECT_EXIST_IMPL(...) SECOND_ARG(__VA_ARGS__)
// We will create MY_DEFINE, but not MY_DEFINE2
#define MY_DEFINE
int main()
{
// We can now use DETECT_EXIST to detect defines.
std::cout << "MY_DEFINE = " << DETECT_EXIST(MY_DEFINE) << std::endl;
std::cout << "MY_DEFINE2 = " << DETECT_EXIST(MY_DEFINE2) << std::endl;
}
This code will produce the output:
MY_DEFINE = 1
MY_DEFINE2 = 0
Since the first one does exist and the second doesn't.
If the macro is set to a value such as 1, you just need to have an alternate version of DETECT_EXIST_TRUE to handle it, with the macro value pasted on the end. For example:
#define DETECT_EXIST_TRUE1 ~,1
Then if you have:
#define MY_DEFINE1 1
Code like this will also work correctly in main:
std::cout << "MY_DEFINE1 = " << DETECT_EXIST(MY_DEFINE1) << std::endl;
#ifndef CONFIG_X
#error "Written for config x"
#endif
// True for config x, hack this about for other configurations
static bool x = 1;
Now it breaks if config is not x. Generally that's better than trying to second-guess what an unnamed configuration which is not X will require.

Why does the C preprocessor consider enum values as equal?

Why does the std::cout line in the following code run even though A and B are different?
#include <iostream>
enum T { A = 1, B = 2 };
// #define A 1
// #define B 2
int main() {
#if (A == B)
std::cout << A << B;
#endif
}
If I use #define instead (as commented out), I get no output as I expect.
Reason for the question:
I want to have a mode selector for some test code in which I can easily change modes by commenting/uncommenting lines on top:
enum T { MODE_RGB = 1, MODE_GREY = 2, MODE_CMYK = 3 };
// #define MODE MODE_RGB
#define MODE MODE_GREY
// #define MODE MODE_CMYK
int main() {
#if (MODE == MODE_RGB)
// do RGB stuff
#elif (MODE == MODE_GREY)
// do greyscale stuff
#else
// do CMYK stuff
#endif
// some common code
some_function(arg1, arg2,
#if (MODE == MODE_RGB)
// RGB calculation for arg3,
#elif (MODE == MODE_GREY)
// greyscale calculation for arg3,
#else
// CMYK calculation for arg3,
#endif
arg4, arg5);
}
I know I can use numeric values e.g.
#define MODE 1 // RGB
...
#if (MODE == 1) // RGB
but it makes the code less readable.
Is there an elegant solution for this?
There are no macros called A or B, so on your #if line, A and B get replaced by 0, so you actually have:
enum T { A = 1, B = 2 };
int main() {
#if (0 == 0)
std::cout << A << B;
#endif
}
The preprocessor runs before the compiler knows anything about your enum. The preprocessor only knows about macros (#define).
This is because the preprocessor works before compile time.
As the enum definitions occur at compile time, A and B will both be defined as empty (pp-number 0) - and thus equal - at pre-processing time, and thus the output statement is included in the compiled code.
When you use #define they are defined differently at pre-processing time and thus the statement evaluates to false.
In relation to your comment about what you want to do, you don't need to use pre-processor #if to do this. You can just use the standard if as both MODE and MODE_GREY (or MODE_RGB or MODE_CMYK) are all still defined:
#include <iostream>
enum T { MODE_RGB = 1, MODE_GREY = 2, MODE_CMYK = 3 };
#define MODE MODE_GREY
int main()
{
if( MODE == MODE_GREY )
std::cout << "Grey mode" << std::endl;
else if( MODE == MODE_RGB )
std::cout << "RGB mode" << std::endl;
else if( MODE == MODE_CMYK )
std::cout << "CMYK mode" << std::endl;
return 0;
}
The other option using only the pre-processor is to do this as #TripeHound correctly answered below.
Identifiers that are not defined macros are interpreted as value 0 in conditional preprocessor directives. Therefore, since you hadn't defined macros A and B, they are both considered 0 and two 0 are equal to each other.
The reason why undefined (to the pre-processor) identifiers are considered 0 is because it allows using undefined macros in the conditional without using #ifdef.
As the other answers said, the C preprocessor doesn't see enums. It expects, and can only understand, macros.
Per the C99 standard, §6.10.1 (Conditional inclusion):
After all replacements due to macro expansion and the defined unary operator have been performed, all remaining identifiers are replaced with the pp-number 0
In other words, in an #if or #elif directive, any macros that cannot be expanded, because they don't exist/are undefined, will behave exactly as if they'd been defined as 0, and therefore will always be equal to each other.
You can catch likely unintended behavior like this in GCC/clang with the warning option -Wundef (you'll probably want to make it fatal with -Werror=undef).
The preprocessor runs before the compiler, which means that the preprocessor doesn't know anything about symbols defined by the compiler and therefore it can't act depending on them.
Other answers explain why what you're trying doesn't work; for an alternative, I'd probably go with:
#define RGB 1
#define GREY 2
#define CMYK 3
#define MODE RGB
#if MODE == RGB
//RGB-mode code
#elif MODE == GREY
//Greyscale code
#elif MODE == CMYK
//CMYK code
#else
# error Undefined MODE
#endif
You might want prefixes on the RGB/GREY/CMYK if there's a danger of clashes with "real" source code.
The posts have explained why, but a possible solution for you that keeps readability might be like this
#define MODE_RGB
int main()
{
#ifdef MODE_RGB
std::cout << "RGB mode" << std::endl;
#elif defined MODE_GREY
std::cout << "Grey mode" << std::endl;
#elif defined MODE_CMYK
std::cout << "CMYK mode" << std::endl;
#endif
}
You just then need to change the macro at the top, to only the macro you are interested in is defined. You could also include a check to make sure that one and only one is defined and if not then and do #error "You must define MODE_RGB, MODE_GREY or MODE_CMYK

asm volatile issue in C/C++ MUD code

I'm working on an old MUD codebase with a friend just as a hobby project, but I'm having issues getting the code to compile in any OS other than debian (x386 specifically). The issue is (mostly) because of a few asm lines that I honestly don't understand enough to modify. The error I receive when trying to compile in VS is "error c2059: syntax error '' line 29. Any idea on how to get this to compile on an x64 OS?
void Execute(int nArgs, ...)
{
if(MAX_FUNCTION_ARGS < nArgs)
throw "Error: CFuncPtr has too many args";
int i;
void *fptrs[MAX_FUNCTION_ARGS], *ptrs[MAX_FUNCTION_ARGS];
va_list ap;
va_start(ap, nArgs);
for(i = 0; i < nArgs; i++)
fptrs[i] = va_arg(ap, void *);
for(i = 0; i < nArgs; i++)
{
ptrs[i] = fptrs[nArgs - i - 1];
// ============== This is the part with the issue
asm volatile("" \ // This is line 29.
"movl %0, %%eax\n\t" \
"pushl %%eax\n\t" \
:
: "r"(ptrs[i])
: "%eax");
// ==============
}
(*funcptr) ();
va_end(ap);
}
This is far from trivial, since x86-64 uses register passing for arguments [and it's a rather ugly solution in the first place, since it's basically assuming no arguments are passed in registers, and that the callee function takes all arguments on the stack].
I would probably avoid the assembly version altogether, and instead of the second for-loop (with the assembly code) write something like:
switch(nArgs)
{
case 0:
(*funcptr)();
break;
case 1:
(*funcptr)(fptrs[0]);
break;
case 2:
(*funcptr)(fptrs[0], fptrs[1]);
break;
... Repeat until MAX_FUNCTION_ARGS is covered.
}
It is unlikely to generate terribly bad code unless MAX_FUNCTION_ARGS is VERY large [in which case you probably want to change the calling convention of funcptr in the first place].

How much one can do with (higher order) macros?

Is it "safe" to give macros names as arguments to other macros to simulate higher order functions?
I.e. where should I look to not shoot myself in the foot?
Here are some snippets:
#define foreach_even(ii, instr) for(int ii = 0; ii < 100; ii += 2) { instr; }
#define foreach_odd(ii, instr) for(int ii = 1; ii < 100; ii += 2) { instr; }
#define sum(foreach_loop, accu) \
foreach_loop(ii, {accu += ii});
int acc = 0;
sum(foreach_even, acc);
sum(foreach_odd, acc);
What about partial application, can I do that? :
#define foreach(ii, start, end, step, instr) \
for(int ii = start; ii < end; ii += step) { instr; }
#define foreach_even(ii, instr) foreach(ii, 0, 100, instr)
#define foreach_odd(ii, instr) foreach(ii, 1, 100, instr)
#define sum(foreach_loop, accu) \
foreach_loop(ii, {accu += ii});
int acc = 0;
sum(foreach_even, acc);
sum(foreach_odd, acc);
And can I define a macro inside a macro?
#define apply_first(new_macro, macro, arg) #define new_macro(x) macro(arg,x)
If you're into using preprocessor as much as possible, you may want to try boost.preprocessor.
But be aware that it is not safe to do so. Commas, for instance, cause a great number of problems when using preprocessors. Don't forget that preprocessors do not understand (or even try to understand) any of the code they are generating.
My basic advice is "don't do it", or "do it as cautiously as possible".
I've implemented a rotten little unit testing framework entirely in c-preprocessor. Several dozen macro, lots of macro is an argument to another macro type stuff.
This kind of thing is not "safe" in a best-practices sense of the word. There are subtle and very powerful ways to shoot yourself in the foot. The unit testing project is a toy that got out of hand.
Don't know if you can nest macro definitions. I doubt it, but I'll go try...gcc doesn't like it, and responds with
nested_macro.cc:8: error: stray '#' in program
nested_macro.cc:3: error: expected constructor, destructor, or type conversion before '(' token
nested_macro.cc:3: error: expected declaration before '}' token
Self plug: If you're interested the unit testing framework can be found at https://sourceforge.net/projects/dut/