一个时髦的c++变量,命名为测试输出



我制作了一些可变输出宏,特别是用于测试输出目的。示例:c++ -code//输出:函数文件(首字符和尾字符)linenumber变量=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.  @}

它们工作得很好,有一些小的限制,可以通过更多的文本分析(限制使用逗号和输出规范)来降低。到目前为止,他们至少在g++1z和c++1z下工作。我的问题:

  1. 主要问题:如何获得宏完全线程安全?
  2. 是否有不需要文本分析的解决方案,例如避免#VA_ARGS让每个参数的名称分开?
  3. 如何区分参数和输出操纵符(必要)?
  4. 对于其他(更新的)c++和c++版本有什么要改变的?
  5. 即使使用本地定义的输出将一整行写入一个本地字符串也不能完全解决并行工作中输出混合的问题-但为什么呢?这个问题将在哪个c++版本中得到解决?我将使用"std::out"给出一个简化的基本版本。将工作得很好,但当然会给出坏的结果,当在并行线程中使用:
#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 == "") std::cout.flush();
else std::cout << postfix; //  << endl; 
#endif
};

是否存在不需要文本分析的解决方案,例如避免#VA_ARGS并将每个参数的名称分开?

您可以使用硬编码限制。

一些实用程序MACRO"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__)

然后,你可以这样做

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__))

演示