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
};
You might do it with hard coded limit.
Some utilities MACRO to "iterate" over
__VA_ARGS__:Then, you might do something like
Demo