a sleek C++ variadic named test output - c++

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

Related

How to join variable-length parameters as a string

I want to pass variable-length parameters in the function, concatenate these parameters with commas, and finally return the form of the string with parentheses. If the parameter type is a string or char *, then automatically With single quotes, how does this work? Thank you!
For example: join (1, 2, "hello", 3, "world") returns the string "(1, 2, \"hello\", 3, \"world\")"
You could create some function templates to do the job.
#include <iostream>
#include <sstream>
#include <type_traits>
// a function that takes a variable amount of arguments
template<typename T, class... Args >
std::string join_helper(const T& t, Args...args) {
std::ostringstream ss;
using type = std::remove_cv_t<std::remove_reference_t<T>>;
// check if " should be added
if constexpr(std::is_same_v<type, const char*> ||
std::is_same_v<type, std::string> ||
std::is_same_v<type, std::string_view>)
{
ss << '"';
}
ss << t; // stream out the current value
if constexpr(std::is_same_v<type, const char*> ||
std::is_same_v<type, std::string> ||
std::is_same_v<type, std::string_view>)
{
ss << '"';
}
// do we have more arguments? if so, add ", " and call join_helper again
if constexpr (sizeof...(args) > 0) {
ss << ", ";
ss << join_helper(args...);
}
return ss.str();
}
// the function you will use that adds ( and ) around the return value from join_helper
template<class... Args>
std::string join(Args...args) {
if constexpr(sizeof...(args) > 0)
return '(' + join_helper(args...) + ')';
else
return "()";
}
int main() {
std::cout
<< join(1, 2.3, "hello", 4, std::string("world")) << '\n'
<< join() << '\n'
;
}
Output:
(1, 2.3, "hello", 4, "world")
()

C++ Input to only accept operator symbols or only numbers

I've been trying to code this as sort of a beginner program for C++ to help me understand the language more but I don't really know how to tackle this.
Basically the program needs to only accept '+', '*', '/', '%' or numbers, otherwise it will say the input is invalid.
Here's what I've done so far
#include <iostream>
#include <string>
using namespace std;
int main()
{
string x;
cout<<"Enter expression: ";
getline(cin,x);
if(x.find('*') != string::npos){
cout<<"Multiplication";
}else if(x.find('/') != string::npos){
cout<<"Division";
}else if(x.find('%') != string::npos){
cout<<"Modulo";
}else if(x.find('+') != string::npos){
cout<<"Addition";
}else{
cout<<"Invalid!";
}
return 0;
}
Definition of the Valid Input
Here I assume that the valid input is given by the following natural statements. First of all, as you mentioned,
Each input must be constructed from *, /, %, + and an integer.
Only zero or one operation. ( So 1+1 is valid. )
For an input of an integer, I also assume
Whitespace characters are allowed in the left and right side of the input string.
Whitespace characters between non-whitespace characters are not allowed.
The first non-whitespace character must be 0, 1, ..., 9 or - (for negative integers).
The second and the subsequent non-whitespace characters must be 0, 1, ..., 8 or 9.
Note that in my assumption the positive sign character +, decimal-point character . are not allowed for integer inputs.
For instance, in this definition,
"123", " 123", "123 " and " -123 " are all valid integer inputs.
"abc", "123a", " 1 23", "+123" and "1.0" are all invalid ones.
Validity Check Function for An Integer
First, to check the validity of the input of an integer, we trim the input and remove left and right whitespaces using the following trimming function: ( If you can use C++17, std::string_view would be more preferable from the performance poin of view.)
#include <string>
std::string trimLR(const std::string& str)
{
const auto strBegin = str.find_first_not_of(" \f\n\r\t\v");
if (strBegin == std::string::npos){
return "";
}
const auto strEnd = str.find_last_not_of(" \f\n\r\t\v");
const auto strRange = strEnd - strBegin + 1;
return str.substr(strBegin, strRange);
}
Next, we define the following simple validity check function isInteger which checks whether the passed string is an integer or not. Here std::isdigit is useful to check whether each character is digits or not.
Please note that various interesting methods are proposed in the past
posts.
#include <string>
#include <algorithm>
bool isInteger(const std::string& s)
{
const auto ts = trimLR(s);
if(ts.empty()){
return false;
}
const std::size_t offset = (ts[0] == '-') ? 1 : 0;
const auto begin = ts.cbegin() + offset;
return (begin != ts.cend()) // false if s is just a negative sign "-"
&& std::all_of(begin, ts.cend(), [](unsigned char c){
return std::isdigit(c);
});
}
Main Function
Now it is easy and straightforward to implement the main function.
The following code will check inputs and work fine.
The next considerations are writing tests and performance tunings:
DEMO(Multiplication)
DEMO(Division)
DEMO(Modulo)
DEMO(Addition)
DEMO(Invalid 1)
DEMO(Invalid 2)
#include <iostream>
int main()
{
std::string x;
std::cout << "Enter expression: ";
std::getline(std::cin, x);
const auto optPos = x.find_first_of("*/%+");
if (optPos == std::string::npos)
{
if(isInteger(x)){
std::cout << "Valid input, " << x;
}
else{
std::cout << "Invalid input, " << x;
}
return 0;
}
const auto left = x.substr(0, optPos);
const auto opt = x.substr(optPos, 1);
const auto right = x.substr(std::min(optPos+1, x.length()-1));
if (!isInteger(left) || !isInteger(right))
{
std::cout
<< "Either `" << left << "`, `" << right
<< "` or both are invalid inputs." << std::endl;
return 0;
}
const auto leftVal = std::stod(left);
const auto rightVal = std::stod(right);
if(opt == "*")
{
std::cout
<< "Multiplication: "
<< x << " = " << (leftVal * rightVal);
}
else if(opt == "/")
{
std::cout
<< "Division: "
<< x << " = " << (leftVal / rightVal);
}
else if(opt == "%")
{
std::cout
<< "Modulo: "
<< x << " = " << (std::stoi(left) % std::stoi(right));
}
else if(opt == "+")
{
std::cout
<< "Addition: "
<< x << " = " << (leftVal + rightVal);
}
return 0;
}

Need some help writing an EMPTY_OR macro

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;
}

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;
}

Return fixed length std::string from integer value

Problem -> To return fixed length string to std::string*.
Target machine -> Fedora 11 .
I have to derive a function which accepts integer value and return fixed lenght string to a string pointer;
for example -> int value are in range of 0 to -127
so for int value 0 -> it shoud display 000
for value -9 -> it should return -009
for value say -50 -> it should return -050
for value say -110 -> it should return -110
so in short , lenght should be same in all cases.
What I have done : I have defined the function according to the requirement which has shown below.
Where I need help: I have derived a function but I am not sure if this is correct approach. When I test it on standalone system on windows side , the exe stopped working after sometimes but when I include this function with the overall project on Linux machine , it works flawlessly.
/* function(s)to implement fixed Length Rssi */
std::string convertString( const int numberRssi, std::string addedPrecison="" )
{
const std::string delimiter = "-";
stringstream ss;
ss << numberRssi ;
std::string tempString = ss.str();
std::string::size_type found = tempString.find( delimiter );
if( found == std::string::npos )// not found
{
tempString = "000";
}
else
{
tempString = tempString.substr( found+1 );
tempString = "-" +addedPrecison+tempString ;
}
return tempString;
}
std::string stringFixedLenght( const int number )
{
std::string str;
if( (number <= 0) && (number >= -9) )
{
str = convertString( number, "00");
}
else if( (number <= -10) && (number >= -99) )
{
str = convertString( number, "0");
}
else
{
str= convertString(number, "");
}
return str;
}
// somewhere in the project calling the function
ErrorCode A::GetNowString( std::string macAddress, std::string *pString )
{
ErrorCode result = ok;
int lvalue;
//some more code like iopening file and reading file
//..bla
// ..bla
// already got the value in lvalue ;
if( result == ok )
{
*pString = stringFixedLenght( lValue );
}
// some more code
return result;
}
You can use I/O manipulators to set the width that you need, and fill with zeros. For example, this program prints 00123:
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
cout << setfill('0') << setw(5) << 123 << endl;
return 0;
}
You have to take care of the negative values yourself, though: cout << setfill('0') << setw(5) << -123 << endl prints 0-123, not -0123. Check if the value is negative, set the width to N-1, and add a minus in front.
How about using std::ostringstream and the standard output formatting manipulators?
std::string makeFixedLength(const int i, const int length)
{
std::ostringstream ostr;
if (i < 0)
ostr << '-';
ostr << std::setfill('0') << std::setw(length) << (i < 0 ? -i : i);
return ostr.str();
}
Note that your examples contradict your description: if the value is -9,
and the fixed length is 3, should the output be "-009" (as in your
example), or "-09" (as you describe)? If the former, the obvious
solution is to just use the formatting flags on std::ostringstream:
std::string
fixedWidth( int value, int width )
{
std::ostringstream results;
results.fill( '0' );
results.setf( std::ios_base::internal, std::ios_base::adjustfield );
results << std::setw( value < 0 ? width + 1 : width ) << value;
return results.str();
}
For the latter, just drop the conditional in the std::setw, and pass
width.
For the record, although I would avoid it, this is one of the rare cases
where printf does something better than ostream. Using snprintf:
std::string
fixedWidth( int value, int width )
{
char buffer[100];
snprintf( buffer, sizeof(buffer), "%.*d", width, value );
return buffer;
}
You'd probably want to capture the return value of snprintf and add
some error handling after it, just in case (but 100 chars is
sufficient for most current machines).
I have nothing against the versions that use streams, but you can do it all yourself more simply than your code:
std::string fixedLength(int value, int digits = 3) {
unsigned int uvalue = value;
if (value < 0) {
uvalue = -uvalue;
}
std::string result;
while (digits-- > 0) {
result += ('0' + uvalue % 10);
uvalue /= 10;
}
if (value < 0) {
result += '-';
}
std::reverse(result.begin(), result.end());
return result;
}
like this?
#include <cstdlib>
#include <string>
template <typename T>
std::string meh (T x)
{
const char* sign = x < 0 ? "-" : "";
const auto mag = std::abs (x);
if (mag < 10) return sign + std::string ("00" + std::to_string(mag));
if (mag < 100) return sign + std::string ("0" + std::to_string(mag));
return std::to_string(x);
}
#include <iostream>
int main () {
std::cout << meh(4) << ' '
<< meh(40) << ' '
<< meh(400) << ' '
<< meh(4000) << '\n';
std::cout << meh(-4) << ' '
<< meh(-40) << ' '
<< meh(-400) << ' '
<< meh(-4000) << '\n';
}
004 040 400 4000
-004 -040 -400 -4000