I have problem of make code working of fold expression in line 18 and line 23
I want make it such as have this result
"1 2 3 4"
"9 0 -1 -200"
"abc"
" world"
"Empty List"
As if the list is empty you will print "Empty List", if not, if the type is char it won't print space and if the type is not char, it will print space in between.
I tried using ((std::cout<<" " << list), ...); but it will print extra space which I don't want so I store in a temp string and later erase it.
Anyone can help?
#include <iostream>
#include <string>
template<int ... intlist>
using IntList = typename Facility<int>::List<intlist...>;
template<char ... charlist>
using CharList = typename Facility<char>::List<charlist...>;
template<short ... shortlist>
using ShortList = typename Facility<short>::List<shortlist...>;
template<unsigned short ... shortlist>
using UnsignedShortList = typename Facility<unsigned short>::List<shortlist...>;
template<long ... list>
using LongList = typename Facility<long>::List<list...>;
template<typename T , typename Comp=std::less<T>>
struct Facility
{
template<T ... list>
struct List
{
static void print()
{
std::string str;
str ="\"";
if(sizeof...(list)== 0)
{
str+="Empty List";
}
else if (std::is_same<T, char>::value)
{
str+=(... + list);
//((std::cout<< list), ...);
}
else
{
str+=((" " + list), ...);
//((std::cout<<" " << list), ...);
str.erase(0,1);
}
str+="\"";
std::cout << str << std::endl;
}
};
};
int main()
{
using List1 = IntList<1,2,3,4>;
using List2 = IntList<9, 0, -1, -200>;
List1::print();
List2::print();
using String1 = CharList<'a', 'b', 'c'>;
using String2 = CharList<' ', 'w', 'o', 'r', 'l', 'd' >;
using EmptyString = CharList<>;
String1::print();
String2::print();
EmptyString::print();
}
As I understand you might use:
template<typename T>
struct Facility
{
template <T ... list>
struct List
{
static void print()
{
std::cout << '"';
if constexpr (sizeof...(list) == 0)
{
std::cout << "Empty List";
}
else if constexpr (std::is_same<T, char>::value)
{
((std::cout << list), ...);
}
else
{
[[maybe_unused]] const char* sep = "";
(((std::cout << sep << list), sep = " "), ...);
}
std::cout << '"' << std::endl;
}
};
};
With usage:
int main() {
Facility<int>::List<>::print();
Facility<int>::List<42, 42>::print();
Facility<char>::List<'h', 'e', 'l', 'l', 'o'>::print();
}
Demo
Another solution could be the use of a std::ostringstream and remove the last char (placing the space in last position)
std::ostringstream oss;
((oss << list << ' '), ...);
str += oss.str().substr(0, oss.str().size()-1);
The following is a full compiling example
#include <string>
#include <iostream>
#include <sstream>
template<typename T , typename Comp=std::less<T>>
struct Facility
{
template<T ... list>
struct List
{
static void print()
{
std::string str;
str = "\"";
if(sizeof...(list)== 0)
{
str += "Empty List";
}
else if (std::is_same<T, char>::value)
{
std::ostringstream oss;
((oss << list), ...);
str += oss.str();
}
else
{
std::ostringstream oss;
((oss << list << ' '), ...);
str += oss.str().substr(0, oss.str().size()-1);
}
str += "\"";
std::cout << str << std::endl;
}
};
};
int main ()
{
Facility<int>::List<1, 2, 3, 4> f;
f.print();
}
Related
#include <bits/stdc++.h>
using namespace std;
#define __deb(X...) (cout << "[" << #X << "]:" << X)
template <typename... type>
void debug(type &&... args)
{
((__deb(args)), ...);
}
int main()
{
int a = 1, b = 3;
debug(a,b);
return 0;
}
I got output like [args]:1[args]:3
but I wanted output like [a]:1[b]:3
One way could be to quote all the macro arguments using #__VA_ARGS__ and parse that string in the C++ function.
Example:
#include <iostream>
#include <sstream>
#include <string>
#include <utility>
template<typename T, typename... Args>
std::string debug_detail(const char* names, T&& var, Args&&... args) {
std::ostringstream builder;
// find variable end
const char* end = names;
while(*end != ',' && *end != '\0') ++end;
// display one variable
(builder << ' ').write(names, end - names) << '=' << var;
// continue parsing?
if constexpr(sizeof...(Args) > 0) {
// recursively call debug_detail() with the new beginning for names
builder << debug_detail(end + 1, std::forward<Args>(args)...);
}
return builder.str();
}
template<typename... Args>
void debug_entry(const char* file, int line, const char* func,
const char* names, Args&&... args) {
std::ostringstream retval;
// common debug info
retval << file << '(' << line << ") " << func << ':';
// add variable info
retval << debug_detail(names, std::forward<Args>(args)...) << '\n';
std::cout << retval.str();
}
// the actual debug macro
#define debug(...) \
debug_entry(__FILE__,__LINE__,__func__,#__VA_ARGS__,__VA_ARGS__)
int main() {
int foo = 1;
const double bar = 2;
const std::string Hello = "world";
debug(foo,bar,Hello);
}
Possible output:
example.cpp(49) main: foo=1 bar=2 Hello=world
Demo
A C++20 version using std::source_location:
#include <source_location>
template<typename... Args>
void debug_entry(const std::source_location location,
const char* names, Args&&... args) {
std::ostringstream retval;
// common debug info
retval << location.file_name() << '(' << location.line() << ','
<< location.column() << ") " << location.function_name() << ':';
// add variable info
retval << debug_detail(names, std::forward<Args>(args)...) << '\n';
std::cout << retval.str();
}
// the actual debug macro
#define debug(...) \
debug_entry(std::source_location::current(), #__VA_ARGS__,__VA_ARGS__)
Demo
Here's my humble attempt, which uses a macro FOO to create a pair of the variable name and its value, and passes the arguments to a variadic function:
#include <utility>
#include <iostream>
#define FOO(var) std::make_pair(std::string(#var), var)
template <typename T>
void __deb(std::pair<std::string, T> arg) { std::cout << "[" << arg.first << "]:" << arg.second; }
template <typename... type>
void debug(std::pair<std::string, type> &&... args)
{
(__deb(args), ...);
}
int main()
{
int a = 1, b = 3;
debug(FOO(a), FOO(b));
}
Demo
Alternatively, to avoid having a macro call FOO for each variable in debug, you could define debug as a macro that accepts #__VA_ARGS__ (string of arguments) and __VA_ARGS__ (argument values). Then parse each variable name and value:
#include <iostream>
#include <sstream>
#include <stdio.h>
#define debug(...) debug_print(#__VA_ARGS__,__VA_ARGS__)
template <typename T>
void __deb(std::istringstream &ss, T arg)
{
//Extract name from stream
std::string name;
std::getline(ss, name, ',');
//trim leading space
const auto pos(name.find_first_not_of(" "));
name.erase(0, pos);
std::cout << "[" << name << "]:" << arg;
}
template <typename... type>
void debug_print(const char* names, type&&...args)
{
std::istringstream ss(names);
(__deb(ss, args), ...);
}
int main()
{
int a = 1, b = 3, c = 4;
debug(a, b, c);
}
Demo
The problem is that the MACRO is used in the context of void debug(type &&... args), which is not familiar with the names a and b.
A possible solution to your problem is to implement a bigger MACRO which gats several vars and calls a sub-MACRO which handles a single var (which you already implemented).
This way the initial MACRO call will happen in the context of the calling function which has the wanted vars
#include <bits/stdc++.h>
using namespace std;
#define __deb(X...) (cout << "[" << #X << "]:" << X)
template <typename... type>
void debug(type &&... args)
{
((__deb(args)), ...);
}
int main()
{
int a = 1, b = 3;
debug(a,b);
return 0;
}
I got output like [args]:1[args]:3
but I wanted output like [a]:1[b]:3
One way could be to quote all the macro arguments using #__VA_ARGS__ and parse that string in the C++ function.
Example:
#include <iostream>
#include <sstream>
#include <string>
#include <utility>
template<typename T, typename... Args>
std::string debug_detail(const char* names, T&& var, Args&&... args) {
std::ostringstream builder;
// find variable end
const char* end = names;
while(*end != ',' && *end != '\0') ++end;
// display one variable
(builder << ' ').write(names, end - names) << '=' << var;
// continue parsing?
if constexpr(sizeof...(Args) > 0) {
// recursively call debug_detail() with the new beginning for names
builder << debug_detail(end + 1, std::forward<Args>(args)...);
}
return builder.str();
}
template<typename... Args>
void debug_entry(const char* file, int line, const char* func,
const char* names, Args&&... args) {
std::ostringstream retval;
// common debug info
retval << file << '(' << line << ") " << func << ':';
// add variable info
retval << debug_detail(names, std::forward<Args>(args)...) << '\n';
std::cout << retval.str();
}
// the actual debug macro
#define debug(...) \
debug_entry(__FILE__,__LINE__,__func__,#__VA_ARGS__,__VA_ARGS__)
int main() {
int foo = 1;
const double bar = 2;
const std::string Hello = "world";
debug(foo,bar,Hello);
}
Possible output:
example.cpp(49) main: foo=1 bar=2 Hello=world
Demo
A C++20 version using std::source_location:
#include <source_location>
template<typename... Args>
void debug_entry(const std::source_location location,
const char* names, Args&&... args) {
std::ostringstream retval;
// common debug info
retval << location.file_name() << '(' << location.line() << ','
<< location.column() << ") " << location.function_name() << ':';
// add variable info
retval << debug_detail(names, std::forward<Args>(args)...) << '\n';
std::cout << retval.str();
}
// the actual debug macro
#define debug(...) \
debug_entry(std::source_location::current(), #__VA_ARGS__,__VA_ARGS__)
Demo
Here's my humble attempt, which uses a macro FOO to create a pair of the variable name and its value, and passes the arguments to a variadic function:
#include <utility>
#include <iostream>
#define FOO(var) std::make_pair(std::string(#var), var)
template <typename T>
void __deb(std::pair<std::string, T> arg) { std::cout << "[" << arg.first << "]:" << arg.second; }
template <typename... type>
void debug(std::pair<std::string, type> &&... args)
{
(__deb(args), ...);
}
int main()
{
int a = 1, b = 3;
debug(FOO(a), FOO(b));
}
Demo
Alternatively, to avoid having a macro call FOO for each variable in debug, you could define debug as a macro that accepts #__VA_ARGS__ (string of arguments) and __VA_ARGS__ (argument values). Then parse each variable name and value:
#include <iostream>
#include <sstream>
#include <stdio.h>
#define debug(...) debug_print(#__VA_ARGS__,__VA_ARGS__)
template <typename T>
void __deb(std::istringstream &ss, T arg)
{
//Extract name from stream
std::string name;
std::getline(ss, name, ',');
//trim leading space
const auto pos(name.find_first_not_of(" "));
name.erase(0, pos);
std::cout << "[" << name << "]:" << arg;
}
template <typename... type>
void debug_print(const char* names, type&&...args)
{
std::istringstream ss(names);
(__deb(ss, args), ...);
}
int main()
{
int a = 1, b = 3, c = 4;
debug(a, b, c);
}
Demo
The problem is that the MACRO is used in the context of void debug(type &&... args), which is not familiar with the names a and b.
A possible solution to your problem is to implement a bigger MACRO which gats several vars and calls a sub-MACRO which handles a single var (which you already implemented).
This way the initial MACRO call will happen in the context of the calling function which has the wanted vars
The system is able to figure out the type of each element using a.type().name() but seriously is not able to print them?
#include <iostream>
#include <vector>
#include <any>
#include <string>
#include <algorithm>
template<typename Last>
void addElement(std::vector<std::any>& container, Last last) {
std::cout << "Last = " << last << std::endl;
container.push_back(last);
}
template<typename First, typename... Rest>
void addElement(std::vector<std::any>& container, First first, Rest... rest) {
std::cout << "Elem = " << first << std::endl;
container.push_back(first);
addElement(container, rest...);
}
template<typename... Ts>
std::vector<std::any> createAnyVector(Ts... ts) {
std::vector<std::any> container;
addElement(container, ts...);
return container;
}
int main() {
std::cout << "ANYVECTOR" << std::endl;
std::vector<std::any> container = createAnyVector("Hello", 3.14, 'A', true, 42);
std::cout << "Number of elements in container = " << container.size() << std::endl; // 5 correct.
for (const auto& a : container) {
std::cout << a.type().name() << ", " << "HERE?" << std::endl;
}
}
If I just write a at the place where now HERE? stands, it returns the error:
No operator << matches these operands
operand types are: std::basic_ostream<char, std::char_traits<char>> << const << std::any
As the comments point out, you cannot do anything directly with std::any, you can just hold them.
If you control the API and have the option to create a wrapper around std::any, you can maintain a function pointer to print the current std::any's contents like so:
struct printable_any {
template <class T>
printable_any(T&& t) : m_val(std::forward<T>(t)) {
m_print_fn = [](std::ostream& os, const std::any& val) {
os << std::any_cast<std::decay_t<T>>(val);
};
}
private:
using print_fn_t = void(*)(std::ostream&, const std::any&);
std::any m_val;
print_fn_t m_print_fn;
friend std::ostream& operator<<(std::ostream& os, const printable_any& val) {
val.m_print_fn(os, val.m_val);
return os;
}
};
Note that even with this, you cannot take a random std::any and print it, you have to construct it yourself along with the function pointer.
Usage:
int main() {
std::vector<printable_any> vals {
"Hello", 3.14, 'A', true, 42
};
for (auto& v : vals) {
std::cout << v << '\n';
}
}
Prints
Hello
3.14
A
1
42
https://godbolt.org/z/o1sejrv1e
Well, what would this print:
struct Foo {
void *p;
};
any v = Foo{};
cout << v << '\n'; // what should this print?
There is no toString equivalent in C++. If you want that behavior, you may create your own hierarchy:
struct Printable {
virtual void print(ostream&) const = 0;
};
auto& operator<<(ostream& os, any const& obj) {
any_cast<Printable const&>(obj).print(os);
return os;
}
Or customize it as you wish and handle the error cases as you like, also add special cases for the integer types if you want, etc.
Does the vector have to be of type any or are you allowed to at least specify the kind of types that are stored in the vector? Because if you can at least specify which types are allowed, I recommend using std::variant.
example: std::vector<variant<int, string>> myVectorVariant;
After that, you can actually print to the console the items in your vector through the use of std::get_if from std::variant. copy-able function below to output your vector for the most of the main primitive types: int, float, char, string.
#include <variant>
#include <vector>
#include <iostream>
using namespace std;
void printVectorVariantValues(vector<variant<int, float, char, string>> arg) {
try {
for (auto val : arg) {
if (const auto intPtr (get_if<int>(&val)); intPtr)
cout << *intPtr << " ";
else if (const auto floatPtr (get_if<float>(&val)); floatPtr)
cout << *floatPtr << " ";
else if (const auto charPtr (get_if<char>(&val)); charPtr)
cout << *charPtr << " ";
else if (const auto stringPtr (get_if<string>(&val)); stringPtr)
cout << *stringPtr << " ";
}
} catch (bad_variant_access err) {
cout << "something" << " ";
}
cout << "DONE" << endl;
}
int main() {
vector<variant<int, float, char, string>> myVectorVariant = {1, 2, 'a', 'b', 3, 0.4f, 0.5f, "c", "DeF", 0.6f, "gHi", "JkL" };
printVectorVariantValues(myVectorVariant);
return 0;
}
/*
output below:
1 2 a b 3 0.4 0.5 c DeF 0.6 gHi JkL DONE
*/
#include <bits/stdc++.h>
using namespace std;
#define __deb(X...) (cout << "[" << #X << "]:" << X)
template <typename... type>
void debug(type &&... args)
{
((__deb(args)), ...);
}
int main()
{
int a = 1, b = 3;
debug(a,b);
return 0;
}
I got output like [args]:1[args]:3
but I wanted output like [a]:1[b]:3
One way could be to quote all the macro arguments using #__VA_ARGS__ and parse that string in the C++ function.
Example:
#include <iostream>
#include <sstream>
#include <string>
#include <utility>
template<typename T, typename... Args>
std::string debug_detail(const char* names, T&& var, Args&&... args) {
std::ostringstream builder;
// find variable end
const char* end = names;
while(*end != ',' && *end != '\0') ++end;
// display one variable
(builder << ' ').write(names, end - names) << '=' << var;
// continue parsing?
if constexpr(sizeof...(Args) > 0) {
// recursively call debug_detail() with the new beginning for names
builder << debug_detail(end + 1, std::forward<Args>(args)...);
}
return builder.str();
}
template<typename... Args>
void debug_entry(const char* file, int line, const char* func,
const char* names, Args&&... args) {
std::ostringstream retval;
// common debug info
retval << file << '(' << line << ") " << func << ':';
// add variable info
retval << debug_detail(names, std::forward<Args>(args)...) << '\n';
std::cout << retval.str();
}
// the actual debug macro
#define debug(...) \
debug_entry(__FILE__,__LINE__,__func__,#__VA_ARGS__,__VA_ARGS__)
int main() {
int foo = 1;
const double bar = 2;
const std::string Hello = "world";
debug(foo,bar,Hello);
}
Possible output:
example.cpp(49) main: foo=1 bar=2 Hello=world
Demo
A C++20 version using std::source_location:
#include <source_location>
template<typename... Args>
void debug_entry(const std::source_location location,
const char* names, Args&&... args) {
std::ostringstream retval;
// common debug info
retval << location.file_name() << '(' << location.line() << ','
<< location.column() << ") " << location.function_name() << ':';
// add variable info
retval << debug_detail(names, std::forward<Args>(args)...) << '\n';
std::cout << retval.str();
}
// the actual debug macro
#define debug(...) \
debug_entry(std::source_location::current(), #__VA_ARGS__,__VA_ARGS__)
Demo
Here's my humble attempt, which uses a macro FOO to create a pair of the variable name and its value, and passes the arguments to a variadic function:
#include <utility>
#include <iostream>
#define FOO(var) std::make_pair(std::string(#var), var)
template <typename T>
void __deb(std::pair<std::string, T> arg) { std::cout << "[" << arg.first << "]:" << arg.second; }
template <typename... type>
void debug(std::pair<std::string, type> &&... args)
{
(__deb(args), ...);
}
int main()
{
int a = 1, b = 3;
debug(FOO(a), FOO(b));
}
Demo
Alternatively, to avoid having a macro call FOO for each variable in debug, you could define debug as a macro that accepts #__VA_ARGS__ (string of arguments) and __VA_ARGS__ (argument values). Then parse each variable name and value:
#include <iostream>
#include <sstream>
#include <stdio.h>
#define debug(...) debug_print(#__VA_ARGS__,__VA_ARGS__)
template <typename T>
void __deb(std::istringstream &ss, T arg)
{
//Extract name from stream
std::string name;
std::getline(ss, name, ',');
//trim leading space
const auto pos(name.find_first_not_of(" "));
name.erase(0, pos);
std::cout << "[" << name << "]:" << arg;
}
template <typename... type>
void debug_print(const char* names, type&&...args)
{
std::istringstream ss(names);
(__deb(ss, args), ...);
}
int main()
{
int a = 1, b = 3, c = 4;
debug(a, b, c);
}
Demo
The problem is that the MACRO is used in the context of void debug(type &&... args), which is not familiar with the names a and b.
A possible solution to your problem is to implement a bigger MACRO which gats several vars and calls a sub-MACRO which handles a single var (which you already implemented).
This way the initial MACRO call will happen in the context of the calling function which has the wanted vars
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")
()