human-readable type_info.name() [duplicate] - c++

This question already has answers here:
Is it possible to print a variable's type in standard C++?
(25 answers)
Closed 3 years ago.
I've compiled the following code with g++, and got output, which written in comments.
template<class T>
void foo(T t) { cout << typeid(t).name() << endl; }
int main() {
foo("f"); //emits "PKc"
foo(string()); //emits "Ss"
}
I know, that type_info.name() isn't standartized, but is there any way to get human-readable results?
Something like the following would be good enought
const char *
class string

You can use abi::__cxa_demangle for that (demangle function taken from here), just remember that the caller is responsible for freeing the return:
#include <cxxabi.h>
#include <typeinfo>
#include <iostream>
#include <string>
#include <memory>
#include <cstdlib>
std::string demangle(const char* mangled)
{
int status;
std::unique_ptr<char[], void (*)(void*)> result(
abi::__cxa_demangle(mangled, 0, 0, &status), std::free);
return result.get() ? std::string(result.get()) : "error occurred";
}
template<class T>
void foo(T t) { std::cout << demangle(typeid(t).name()) << std::endl; }
int main() {
foo("f"); //char const*
foo(std::string()); //std::string
}
Example on ideone.

Related

std::variant cout in C++

I am relatively new to CPP and have recently stumbled upon std::variant for C++17.
However, I am unable to use the << operator on such type of data.
Considering
#include <iostream>
#include <variant>
#include <string>
using namespace std;
int main() {
variant<int, string> a = "Hello";
cout<<a;
}
I am unable to print the output. Is there any short way of doing this? Thank you so much in advance.
You can use std::visit if you don't want to use std::get.
#include <iostream>
#include <variant>
struct make_string_functor {
std::string operator()(const std::string &x) const { return x; }
std::string operator()(int x) const { return std::to_string(x); }
};
int main() {
const std::variant<int, std::string> v = "hello";
// option 1
std::cout << std::visit(make_string_functor(), v) << "\n";
// option 2
std::visit([](const auto &x) { std::cout << x; }, v);
std::cout << "\n";
}
use std::get
#include <iostream>
#include <variant>
#include <string>
using namespace std;
int main() {
variant<int, string> a = "Hello";
cout << std::get<string>(a);
}
If you want to get automatically, it can't be done without knowing its type. Maybe you can try this.
string s = "Hello";
variant<int, string> a = s;
cout << std::get<decltype(s)>(a);
#include <iostream>
#include <variant>
#include <string>
int main( )
{
std::variant<int, std::string> variant = "Hello";
std::string string_1 = std::get<std::string>( variant ); // get value by type
std::string string_2 = std::get<1>( variant ); // get value by index
std::cout << string_1 << std::endl;
std::cout << string_2 << std::endl;
//may throw exception if index is specified wrong or type
//Throws std::bad_variant_access on errors
//there is also one way to take value std::visit
}
Here is the description link: https://en.cppreference.com/w/cpp/utility/variant

Printing Unicode Japanese characters with WriteConsoleW [duplicate]

This question already has answers here:
printing Unicode characters C++
(3 answers)
Closed 6 years ago.
So, I'm trying to print some Japanese characters. I tried every possible thing. What am I missing?
#include <windows.h>
#include <string>
template<typename T>
void printW(const T* text) {
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), text, std::char_traits<T>::length(text), 0, 0);
}
template<typename T>
void print(const T* text) {
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), text, std::char_traits<T>::length(text), 0, 0);
}
int main()
{
//const char* text = "こんにちは\n";
const wchar_t* textL = L"こんにちは\n";
const char16_t* textu = u"こんにちは\n";
const char32_t* textU = U"こんにちは\n";
//printW(text);
printW(textL);
printW(textu);
printW(textU);
}
WinAPI not needed, also you're using the wrong types.
#include <iostream>
#include <string>
int main()
{
std::string text{u8"こんにちは"};
std::cout << text;
}
Live example
If you need to use the WinAPI, minimal modification is needed:
#include <windows.h>
#include <string>
template<typename T>
void print(const T* text) {
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), text, std::char_traits<T>::length(text), 0, 0);
}
int main()
{
auto text = u8"こんにちは\n";
print(text);
}
disclaimer: not tested on actual windows machine

BOOST_PP_REPEAT with boost::fusion::size

I want to iterate in compile time over struct and write to output number of iteration. Just to mention - in real case I will pass some more parameters in data.
#include <iostream>
#include <string>
#include <vector>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/size.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
struct MyStruct
{
int x;
int y;
};
BOOST_FUSION_ADAPT_STRUCT(
MyStruct,
(int, x)
(int, y)
)
#define PRINT(unused, number, data) \
std::cout << number << std::endl;
int main()
{
MyStruct s;
std::cout << boost::fusion::size(s) << std::endl;
//line below works - it iterate and write output
BOOST_PP_REPEAT(2, PRINT, "here I will pass my data")
//this won't compile
//BOOST_PP_REPEAT(boost::fusion::size(s), PRINT, "here i will pass my data")
}
How to fix problematic line so it will work when I will add more members in structure? I need solution for C++03 :(
Instead of using BOOST_PP_REPEAT, you can use the boost::fusion::for_each which goes through every element. example:
#include <iostream>
#include <string>
#include <vector>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/size.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
struct MyStruct {
int x;
int y;
};
BOOST_FUSION_ADAPT_STRUCT(
MyStruct,
(int, x)
(int, y)
)
template<typename Data>
struct PrintWithData {
PrintWithData(Data data) : data(data) {}
template<typename T>
operator()(const T& thingToBePrinted)
{
std::cout << thingToBePrinted << std::endl;
}
Data data;
};
int main()
{
MyStruct s;
//this will compile
boost::fusion::for_each(s, PrintWithData<std::string>("here I will pass my data"));
}
Here is exact solution for this problem (asked more general question later, and found answear which solve this problem too): https://stackoverflow.com/a/31713778/4555790

Is it possible to reroute lambda to wrap it in a wrapper class?

I was tinkering with a vector of std::function like this:
#include "stdafx.h"
#include <stdexcept>
#include <functional>
#include <iostream>
#include <vector>
typedef std::function<void(int)> FuncType;
std::vector<FuncType> container;
int _tmain(int argc, _TCHAR* argv[])
{
container.push_back([](int i){std::cout << i+1 << std::endl;});
container.push_back([](int i){std::cout << i+42 << std::endl;});
for(auto & o : container)
{
o(4);
}
return 0;
}
which basically just returns 5 and 46 and was thinking whether I can change the declaration of the container to some sort of wrapper class but to maintain the push back of the lambdas (= not changing anything else except declaration).
Currently I tried to implement some stub wrapper doing nothing in particular which should just compile, but it seems that the conversion from lambda to Wrapper cannot be done implicitly.
#include "stdafx.h"
#include <stdexcept>
#include <functional>
#include <iostream>
#include <vector>
typedef std::function<void(int)> FuncType;
template<class T>
class Wrapper
{
public:
Wrapper(T t)
{
_t = t;
}
void operator()(int i) const
{
_t(i);
}
protected:
T & _t;
};
std::vector<Wrapper<FuncType>> container; // Only line changed
int _tmain(int argc, _TCHAR* argv[])
{
container.push_back([](int i){std::cout << i+1 << std::endl;});
container.push_back([](int i){std::cout << i+42 << std::endl;});
for(auto & o : container)
{
o(4);
}
return 0;
}
The goal here is to wrap the call to o(int)and output some diagnostics e.g.
o.target_type().name() or performance values etc but without altering the push_back into the container to Wrapper (avoiding macro magic too)
Note: As I am using VS 2012 where variadic template arguments are not yet implemented, the standard MS std::function resorted to some macro magic like _VARIADIC_EXPAND_P1_1(_CLASS_FUNC_CLASS_1, , , , ) to provider operator()
You're trying to go through two user-defined conversions, and that's illegal in C++. Instead, make the constructor a constrained template. See below:
#include <functional>
#include <utility>
#include <iostream>
#include <vector>
#include <type_traits>
typedef std::function<void(int)> FuncType;
template<class T>
class Wrapper
{
public:
template<typename U,
typename std::enable_if<
std::is_constructible<T, U>::value,
int
>::type = 0>
Wrapper(U t)
: _t(std::move(t))
{}
void operator()(int i) const
{
_t(i);
}
private:
T _t;
};
std::vector<Wrapper<FuncType>> container; // Only line changed
int main(int argc, char* argv[])
{
container.push_back([](int i){std::cout << i+1 << std::endl;});
container.push_back([](int i){std::cout << i+42 << std::endl;});
for(auto & o : container)
{
o(4);
}
}

passing struct parameter by reference c++

how can i pass a struct parameter by reference c++, please see below the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
struct TEST
{
char arr[20];
int var;
};
void foo(char * arr){
arr = "baby"; /* here need to set the test.char = "baby" */
}
int main () {
TEST test;
/* here need to pass specific struct parameters, not the entire struct */
foo(test.arr);
cout << test.arr <<endl;
}
The desired output should be baby.
I would use std::string instead of c arrays in c++
So the code would look like this;
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
using namespace std;
struct TEST
{
std::string arr;
int var;
};
void foo(std::string& str){
str = "baby"; /* here need to set the test.char = "baby" */
}
int main () {
TEST test;
/* here need to pass specific struct parameters, not the entire struct */
foo(test.arr);
cout << test.arr <<endl;
}
That's not how you want to assign to arr.
It's a character buffer, so you should copy characters to it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
using namespace std;
struct TEST
{
char arr[20];
int var;
};
void foo(char * arr){
strncpy(arr, "Goodbye,", 8);
}
int main ()
{
TEST test;
strcpy(test.arr, "Hello, world");
cout << "before: " << test.arr << endl;
foo(test.arr);
cout << "after: " << test.arr << endl;
}
http://codepad.org/2Sswt55g
It looks like you are using C-strings. In C++, you should probably look into using std::string. In any case, this example is passed a char array. So in order to set baby, you will need to do it one character at a time (don't forget \0 at the end for C-strings) or look into strncpy().
So rather than arr = "baby" try strncpy(arr, "baby", strlen("baby"))
It won't work for you beause of the reasons above, but you can pass as reference by adding a & to the right of the type. Even if we correct him at least we should answer the question. And it wont work for you because arrays are implicitly converted into pointers, but they are r-value, and cannot be converted into reference.
void foo(char * & arr);