Need some help writing an EMPTY_OR macro - c++

I'm trying to code a macro called EMPTY_OR, which will return the first argument, but if it's empty, it will return the second one.
Here's what I have so far:
#include <iostream>
#define EMPTY_OR(x, y) ( (sizeof(#x) > sizeof("")) ? (x) : (y) )
#define TEST(x, y) EMPTY_OR(y, x)
using namespace std;
int main()
{
int four = TEST(4, );
int eight = TEST(4, 8);
cout << "four: " << four << endl;
cout << "eight: " << eight << endl;
return 0;
}
It's close, but it doesn't work because the first line of the main function expands to the following:
( (sizeof("") > sizeof("")) ? () : (4) )
The condition is never true, so () is never evaluated. I shouldn't care about it, but the compiler does, and it shows an error.
How can I solve it with the most straightforward and standard-compliant (or at least MSVC-compliant) way?

If I'm understanding what you're trying to do correctly, I'd remove the sizeof and just check if the first character in the string is \0;
#define EMPTY_OR(x, y) ( #x[0] ? (x+0) : (y) )

Here's a solution adapted from this article and without Boost that works on anything that I can think of that you can pass:
#define CAT(a, b) CAT_(a, b)
#define CAT_(a, b) a##b
#define IF(cond, t, f) CAT(IF_, cond)(t, f)
#define IF_1(t, f) t
#define IF_0(t, f) f
#define COMMA(x) ,
#define ARG3(a, b, c, ...) c
#define HAS_COMMA(x) ARG3(x, 1, 0,)
#define EMPTY(x) EMPTY_(HAS_COMMA(COMMA x ()))
#define EMPTY_(x) HAS_COMMA(CAT(EMPTY_, x))
#define EMPTY_1 ,
#define EMPTY_OR(x, y) IF(EMPTY(x), y, x)
#define TEST(x, y) EMPTY_OR(y, x)
#include <iostream>
using namespace std;
int main()
{
int t = TEST(1==, ) 1;
int f = TEST(1==, 0==) 1;
cout << "t: " << t << endl;
cout << "f: " << f << endl;
return 0;
}

Related

Change C/C++ Preprocessor priority

I want to change the priority of the preprocessor define process.
see the following code:
#include <iostream>
#include <sstream>
#define $(x) << x <<
#define f(x) (#x)
int main()
{
auto world = "universe!";
std::stringstream ss;
ss << f(Hello $(world)) << std::endl;
std::cout << ss.str();
return 0;
}
The code run, but the 'f' macro will always processed before the '$' macro.
The current output:
Hello $(world)
Expected output:
Hello universe!
Thx.
"Solving" the problem:
#include <iostream>
#include <sstream>
#define $(x) << " " << x
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define f(x, y) TOSTRING(x) y
int main()
{
auto world = "universe!";
std::stringstream ss;
ss << f(Hello, $(world)) << std::endl;
std::cout << ss.str();
return 0;
}
Output:
Hello universe!
You might "delay" expansion with extra indirection:
#define $(x) << x <<
#define STRINGIFY(x) #x
#define f(x) STRINGIFY(x)
but you won't get your expected result but Hello << world << Demo
Without changing your MACRO, you might already get your result by "fixing" your parenthesis (and surrounding):
ss << f(Hello) " " $(world) /*<<*/ std::endl;
Demo.

a sleek C++ variadic named test output

I've made some variadic output macros, especially for test output purposes.
Examples: C++-code // output: function file(first and last char) linenumber variable=value
L(i,b); // result e.g. {evenRCpower#ih2943: i=36 b=1 #}
L(hex,pd,dec,check.back(),even,"e.g.");
// result e.g.: {way#ih3012: pd=babbbaba check.back()=15216868001 even=1 e.g. #}
They are working fine, having some minor restrictions, which can be lowered by more text analysis (restricted usage of comma and output specifications).
Up to now, they are working at least under g++1z and c++1z.
My questions:
Main question: How to get the macro completely thread safe?
Is there a solution needing no textual analysis, e.g. to avoid #VA_ARGS and get the names for every parameter separated?
How to distinguish parameters from output manipulators (necessary)?
What's to change for other (newer) C++ and g++ versions?
Even to write one complete line into one local string using a locally defined outstream isn't completely solving the problem of output mixing in parallel work - but why? In which C++ version this problem will be solved?
I'll give a simplified base version with use of "std::out" will work fine, but of course give bad results, when used in parallel threads:
#define WO_IS 1
#define L(...) locate(__FILE__,__LINE__,__func__,"\n{",": "," #}\n",#__VA_ARGS__,##__VA_ARGS__)
string argTExcludes = " hex dec std::hex std::dec ", funcExcludes = " setprecision ";
string argT(const string sarg,int &nextpos) { // NO exact analysis!! Simple strings and chars allowed, but parameters with commata like in f(x,y,"A,",','): crazy output !!
int i = nextpos+1, pos = i, follow = 0; string nom; bool apo = false;
for (; i < sarg.size(); i++)
if(sarg.at(i) == ' ') { ;
} else if ((sarg.at(i) == ',')||(i == (sarg.size()-1))) {
nom = sarg.substr(pos,i-pos);
if (argTExcludes.find(nom) != std::string::npos) { nextpos = i; return ""; };
break;
} else {
if ((sarg.at(i) != ' ') && (!follow++) && ((sarg.at(i) == '"')||(sarg.at(i) == '\'')) ) apo = true;
if ((sarg.at(i) == '"') && ( (i==0)||((i > 0) && (sarg.at(i-1) != '\'')) )) { i++; while ((sarg.at(i) != '"') && (i < sarg.size())) i++; };
if (sarg.at(i) == '(') {
nom = sarg.substr(pos,i-pos); if (funcExcludes.find(nom) != std::string::npos) apo = true;
};
};
nextpos = i;
return (apo)?"":sarg.substr(pos,i-pos)+"=";
};
template <typename... Ts>
inline void locate(string ort,long line,string funct,const string prefix, const string trenner, const string postfix, string sarg, Ts... args)
{
#if WO_IS > 0 // all range restrictions abandoned
int pos = -1; bool apo; sarg += ",";
std::ios_base::fmtflags f( cout.flags() );
std::cout << prefix << funct << '#' << ort[0] << ort.back() << dec << line << trenner;
cout.flags( f );
((std::cout << argT(sarg,pos) << args << ' '), ...); // forbidden: endl - it will give syntax error even when no blank at end
// ((std::cout << argT(sarg,pos); std::cout << args; std::cout << ' '), ...); // forbidden: endl - it will also give syntax error
if (postfix == "\0") std::cout.flush();
else std::cout << postfix; // << endl;
#endif
};
Is there a solution needing no textual analysis, e.g. to avoid #VA_ARGS and get the names for every parameter separated?
You might do it with hard coded limit.
Some utilities MACRO to "iterate" over __VA_ARGS__:
#define COUNT_VA_ARGS(...) TAKE_10(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define TAKE_10(_1, _2, _3, _4, _5, _6, _7, _8, _9, N,...) N
#define JOIN(a, b) JOIN_H(a, b)
#define JOIN_H(a, b) a ## b
#define WRAP_VA_ARGS_0(wrap)
#define WRAP_VA_ARGS_1(wrap, x0) wrap(x0)
#define WRAP_VA_ARGS_2(wrap, x0, x1) wrap(x0), wrap(x1)
#define WRAP_VA_ARGS_3(wrap, x0, x1, x2) wrap(x0), wrap(x1), wrap(x2)
#define WRAP_VA_ARGS_4(wrap, x0, x1, x2, x3) wrap(x0), wrap(x1), wrap(x2), wrap(x3)
#define WRAP_VA_ARGS_5(wrap, x0, x1, x2, x3, x4) wrap(x0), wrap(x1), wrap(x2), wrap(x3), wrap(x4)
// ...
// Call into one of the concrete ones above
#define WRAP_VA_ARGS(wrap, ...) JOIN(WRAP_VA_ARGS_, COUNT_VA_ARGS(__VA_ARGS__))(wrap, __VA_ARGS__)
Then, you might do something like
template <typename... Ts>
void print(std::source_location loc, const Ts&...args)
{
std::cout << loc.function_name() << ":" << loc.line() << std::endl;
((std::cout << args << " "), ...) << std::endl;
}
#define NAMED_PAIR(x) #x, x
#define PRINT(...) print(std::source_location::current(), WRAP_VA_ARGS(NAMED_PAIR, __VA_ARGS__))
Demo

Identifier Not defined in Macro

I was trying the below program
#include <iostream>
using namespace std;
#define MKSTR(x) #x
#define CONCATE( x , y ) (x)##(y)
int main()
{
int xy = 100;
cout << MKSTR(HELLO C++) << endl;
cout << CONCATE(HELLO,C++) << endl;
cout << CONCATE(x,y) << endl;
return 0;
}
and getting the error
error C2065: 'HELLO' : undeclared identifier
. I don't see see why the VS 2012 compiler is expecting the macro argument or is treating them as identifier. Also the MKSTR macro worked fine but the CONCATE macro is giving me trouble. Can't understand why compiler is doing so.
You need to concatenate symbols first, and then expand it in a string, like this (compiles in GCC 4.8.1) :
#include <iostream>
using namespace std;
#define MKSTR(x) #x
#define CONCATE( x , y ) x ## y
#define CONCATESTR( x , y ) MKSTR(x ## y)
int main()
{
int xy = 100;
cout << MKSTR(HELLO C++) << endl;
cout << CONCATESTR(HELLO,C++) << endl;
cout << CONCATE(x,y) << endl;
return 0;
}
output :
HELLO C++
HELLOC++
100
EDIT :
So for the question of why MKSTR(CONCAT(...)) is not working, the reason is because of the expansion order of macros.
Because CONCAT is a parameter of MKSTR and MKSTR uses operator #, the argument is not expanded but instead immediately stringified. You could do this instead to make it work :
#include <iostream>
using namespace std;
#define CONCATE( x , y ) x ## y
#define MKSTR(x) #x
#define MKSTR2(x) MKSTR(x)
#define CONCATESTR( x , y ) MKSTR(x ## y)
int main()
{
int xy = 100;
cout << MKSTR2(HELLO C++) << endl;
cout << MKSTR2(CONCATE(HELLO,C++)) << endl;
cout << CONCATE(x,y) << endl;
return 0;
}
and it will output what you expect.

Using MACRO for creating strings (e.g. array index) dynamically inside a for loop

I want to dynamically create strings using MACRO. e.g. if I have int i in range of 1:n and string "testArray". I should be able to create testArray[0],testArray[1], ... testarray[n-1]
Please let me know if it is possible.
Below is sample code :
void fun2(int x,std::string name)
{
/*do something*/
}
void fun1()
{
for (unsigned int i = 0 ;i < 5 ; ++i )
{
// I want to create a MACRO such that it create "testArray[0]","testArray[1]",..."testArray[4]" etc.
fun2(x,CREATE_ARRAY_ELEM ("testArray",i));
}
}
I tried below but it does not work :
#define STR1(x) #x
#define CREATE_INDEX(paramName,elementIndex) #paramName << "[" << elementIndex << "]"
#define CREATE_ARRAY_ELEM(paramName,elementIndex) CREATE_INDEX(paramName,elementIndex)
#define STRINGIZE_1(x) STR1(x)
You appear to be wanting to create the string literals "testArray[0]", "testArray[1]", etc.. at compile time. Thats not going to happen. You could easily accomplish this at runtime using an ostringstream, but I don't think that is what you're looking for.
If it is what you're looking for, then...
#include <iostream>
#include <sstream>
using namespace std;
static std::string array_str(const char* s, unsigned int i)
{
std::ostringstream oss;
oss << s << '[' << i << ']';
return oss.str();
}
void fun2(int x, const std::string& name)
{
std::cout << x << ':' << name << std::endl;
}
void fun1()
{
for (unsigned int i = 0 ;i < 5 ; ++i )
{
fun2(i, array_str("testArray", i));
}
}
Test Output
0:testArray[0]
1:testArray[1]
2:testArray[2]
3:testArray[3]
4:testArray[4]
you can do like this..means in macros itself you have to display the desired string ..
#include<iostream>
#define STR1(x) #x
#define CREATE_INDEX(paramName,elementIndex) cout <<paramName<< "[" << elementIndex << "]"
#define CREATE_ARRAY_ELEM(paramName,elementIndex) CREATE_INDEX(paramName,elementIndex)
#define STRINGIZE_1(x) STR1(x)
using namespace std;
int main()
{
int testArray;
for (unsigned int i = 0 ;i < 5 ; ++i )
{
// I want to create a MACRO such that it create "testArray[0]","testArray[1]",..."testArray[4]" etc.
CREATE_ARRAY_ELEM ("testArray",i);
}
return 1;
}

Preprocessor stringificaton of a character

Is it possible to stringify a character in a preprocessor macro without it including the (')s
example:
#define S(name, chr) const char * name = #name chr
usage:
S(hello, 'W'); //should expand to 'const char * hello = "helloW"
Thanks a bunch!,
Andrew
You don't need to, because in C adjacent string constants are merged.
ie.
const char *hello = "hello" "W";
is equivalent to
const char *hello = "helloW";
so your current macro is fine - just call it like so:
S(hello, "W");
Here are three ways. None use a single-quoted char, though:
#include <iostream>
#define S1(x, y) (#x #y)
#define S2(x, y) (#x y)
#define S3(x, y) (x y)
int main(void)
{
std::cout << S1(hello, W) << std::endl;
std::cout << S2(hello, "W") << std::endl;
std::cout << S3("hello", "W") << std::endl;
};
All output:
helloW