How to access parent scopes recursively? - c++

I tried to do a fancy macro to have some debug informations: The name of the scope you currently are! This can be picked up by e.g. an assert. I tried to made it recursive:
// Global namespace
struct ScopeDef{ static const char* GetName() {return "";} };
typedef ScopeDef ScopeDefParent;
// Macro to place into your namespace/scope
#define NG_SCOPEDEF(scopename) \
struct ScopeDef { \
static const char* GetName() {return scopename;} \
typedef ScopeDefParent Parent; \
}; \
typedef ScopeDef ScopeDefParent;
And using it like:
// Recursive template for testing
template< class T > void PrintImpl() {
PrintImpl< T::Parent >();
printf("::%s", T::GetName() );
}
template<> void PrintImpl< ::ScopeDef >() {}
template< class T > void PrintS() { PrintImpl<T>(); printf("\n");}
// Lets try it:
namespace First {
NG_SCOPEDEF( "First" );
namespace Second {
NG_SCOPEDEF( "Second" );
static void AFun() {
// This prints "::First::Second"
PrintS<ScopeDef>();
}
}
struct Third {
NG_SCOPEDEF( "Third" );
static void BFun() {
// This is endless recursion
PrintS<ScopeDef>();
}
};
}
It doesn't work in class scopes, because the order of definitions don't matter.
This is not a good solution. So is there a way to access the parent scope in a way? In regular code I would just qualify ("::First::ScopeDef"), but that's nothing for a macro.

You could do something like this in C++, where you put in the macro whenever you open a scope and let the destructor take care of cleanup when the scope exits. This example will print out the full scope to stderr, and the output of this code is as follows.
main
main::First
main::First::Second
main::First::Second::DummyClass::DummyFunction
main::First
main
Here is the code:
#include <stdio.h>
class NG_SCOPE_CLASS;
NG_SCOPE_CLASS* NG_SCOPE_END = 0;
class NG_SCOPE_CLASS
{
public:
NG_SCOPE_CLASS(const char* scope)
{
_scope = scope;
_prev = NG_SCOPE_END;
NG_SCOPE_END = this;
}
~ NG_SCOPE_CLASS()
{
NG_SCOPE_END = _prev;
}
void PrintScope()
{
if(_prev)
{
_prev->PrintScope();
fprintf(stderr, "::");
}
fprintf(stderr, "%s", _scope);
}
private:
NG_SCOPE_CLASS* _prev;
const char* _scope;
};
#define NG_SCOPE_PRINT { if(NG_SCOPE_END) { NG_SCOPE_END->PrintScope(); fprintf(stderr, "\n"); } }
#define NG_SCOPE(X) NG_SCOPE_CLASS _NG_SCOPE_CLASS(X)
// THAT'S IT FOR THE DEFINITIONS ABOVE, BELOW IS JUST SOME SAMPLE CODE.
class DummyClass
{
public:
void DummyFunction()
{
NG_SCOPE("DummyClass::DummyFunction");
NG_SCOPE_PRINT;
}
};
int main(int argc, const char* argv[])
{
NG_SCOPE("main");
NG_SCOPE_PRINT;
{
NG_SCOPE("First");
NG_SCOPE_PRINT;
{
NG_SCOPE("Second");
NG_SCOPE_PRINT;
DummyClass theDummyInstance;
theDummyInstance.DummyFunction();
}
NG_SCOPE_PRINT;
}
NG_SCOPE_PRINT;
}

For completeness, our working solution:
#if defined(_MSC_VER)
// GCC solution below. Note MSVC gives warning about unused typedefs but can be suppressed.
#define NG_SCOPEDEF(scopename) \
struct ScopeDefTag { static const char* Name(){return (scopename);}; }; \
typedef ::Scopes::Impl< ScopeDefTag, ScopeDef > ScopeDefHelper; \
struct ScopeDef : ScopeDefHelper {}
#else
// GCC seems to not look ahead.
#define NG_SCOPEDEF(scopename) \
struct ScopeDefTag { static const char* Name(){return (scopename);}; struct SDH : ::Scopes::Impl< ScopeDefTag, ScopeDef >{}; }; \
struct ScopeDef : ScopeDefTag::SDH {}
#endif
namespace Scopes {
struct Chain {
const char* const m_Lit;
const Chain* const m_Prev;
Chain(const char* lit, const Chain* prev) :m_Lit(lit), m_Prev(prev) {}
};
template< bool DMY = true >
struct RootScopeDef
{
static const Chain chain;
static const Chain* Get() { return &chain; }
};
// Being template just to have this in header:
template< bool DMY > const Chain RootScopeDef<DMY>::chain = Chain( "", 0 );
template< class TAG, class PARENT >
struct Impl {
static const Chain chain;
static const Chain* Get() { return &chain; }
typedef PARENT Parent;
};
template< class TAG, class PARENT >
const Chain Impl<TAG, PARENT>::chain = Chain( TAG::Name(), &PARENT::chain );
} // namespace
// Global namespace
typedef Scopes::RootScopeDef<> ScopeDef;
It is based on loopholes in the compiler and is not standard compliant! MSVS thinks that the ScopeDef used as template argument isn't the following one, since it is depending on that very typedef, so it resolves to the parent one, which will be shadowed after. This also works when the macro is placed in a template, because MSVS instantiates them lazily. GCC instead seems to just not look ahead and resolves the base of SDH to the correct one. MSVS would produce an infinite loop of m_Prev references here.
Bottom line: this gives you a nice way to print out namespaces and classes for debugging purposes, but also serves as types for e.g. specializations of templates!

Related

How do i find the struct name from the instance? [duplicate]

Is it possible to get the object name too?
#include<cstdio>
class one {
public:
int no_of_students;
one() { no_of_students = 0; }
void new_admission() { no_of_students++; }
};
int main() {
one A;
for(int i = 0; i < 99; i++) {
A.new_admission();
}
cout<<"class"<<[classname]<<" "<<[objectname]<<"has "
<<A.no_of_students<<" students";
}
where I can fetch the names, something like
[classname] = A.classname() = one
[objectname] = A.objectname() = A
Does C++ provide any mechanism to achieve this?
You can display the name of a variable by using the preprocessor. For instance
#include <iostream>
#define quote(x) #x
class one {};
int main(){
one A;
std::cout<<typeid(A).name()<<"\t"<< quote(A) <<"\n";
return 0;
}
outputs
3one A
on my machine. The # changes a token into a string, after preprocessing the line is
std::cout<<typeid(A).name()<<"\t"<< "A" <<"\n";
Of course if you do something like
void foo(one B){
std::cout<<typeid(B).name()<<"\t"<< quote(B) <<"\n";
}
int main(){
one A;
foo(A);
return 0;
}
you will get
3one B
as the compiler doesn't keep track of all of the variable's names.
As it happens in gcc the result of typeid().name() is the mangled class name, to get the demangled version use
#include <iostream>
#include <cxxabi.h>
#define quote(x) #x
template <typename foo,typename bar> class one{ };
int main(){
one<int,one<double, int> > A;
int status;
char * demangled = abi::__cxa_demangle(typeid(A).name(),0,0,&status);
std::cout<<demangled<<"\t"<< quote(A) <<"\n";
free(demangled);
return 0;
}
which gives me
one<int, one<double, int> > A
Other compilers may use different naming schemes.
use typeid(class).name
// illustratory code assuming all includes/namespaces etc
#include <iostream>
#include <typeinfo>
using namespace std;
struct A{};
int main(){
cout << typeid(A).name();
}
It is important to remember that this
gives an implementation defined names.
As far as I know, there is no way to get the name of the object at run time reliably e.g. 'A' in your code.
EDIT 2:
#include <typeinfo>
#include <iostream>
#include <map>
using namespace std;
struct A{
};
struct B{
};
map<const type_info*, string> m;
int main(){
m[&typeid(A)] = "A"; // Registration here
m[&typeid(B)] = "B"; // Registration here
A a;
cout << m[&typeid(a)];
}
To get class name without mangling stuff you can use func macro in constructor:
class MyClass {
const char* name;
MyClass() {
name = __func__;
}
}
Do you want [classname] to be 'one' and [objectname] to be 'A'?
If so, this is not possible. These names are only abstractions for the programmer, and aren't actually used in the binary code that is generated. You could give the class a static variable classname, which you set to 'one' and a normal variable objectname which you would assign either directly, through a method or the constructor. You can then query these methods for the class and object names.
Just write simple template:
template<typename T>
const char* getClassName(T) {
return typeid(T).name();
}
struct A {} a;
void main() {
std::cout << getClassName(a);
}
You could try using "typeid".
This doesn't work for "object" name but YOU know the object name so you'll just have to store it somewhere. The Compiler doesn't care what you namned an object.
Its worth bearing in mind, though, that the output of typeid is a compiler specific thing so even if it produces what you are after on the current platform it may not on another. This may or may not be a problem for you.
The other solution is to create some kind of template wrapper that you store the class name in. Then you need to use partial specialisation to get it to return the correct class name for you. This has the advantage of working compile time but is significantly more complex.
Edit: Being more explicit
template< typename Type > class ClassName
{
public:
static std::string name()
{
return "Unknown";
}
};
Then for each class somethign liek the following:
template<> class ClassName<MyClass>
{
public:
static std::string name()
{
return "MyClass";
}
};
Which could even be macro'd as follows:
#define DefineClassName( className ) \
\
template<> class ClassName<className> \
{ \
public: \
static std::string name() \
{ \
return #className; \
} \
}; \
Allowing you to, simply, do
DefineClassName( MyClass );
Finally to Get the class name you'd do the following:
ClassName< MyClass >::name();
Edit2: Elaborating further you'd then need to put this "DefineClassName" macro in each class you make and define a "classname" function that would call the static template function.
Edit3: And thinking about it ... Its obviously bad posting first thing in the morning as you may as well just define a member function "classname()" as follows:
std::string classname()
{
return "MyClass";
}
which can be macro'd as follows:
DefineClassName( className ) \
std::string classname() \
{ \
return #className; \
}
Then you can simply just drop
DefineClassName( MyClass );
into the class as you define it ...
You can try this:
template<typename T>
inline const char* getTypeName() {
return typeid(T).name();
}
#define DEFINE_TYPE_NAME(type, type_name) \
template<> \
inline const char* getTypeName<type>() { \
return type_name; \
}
DEFINE_TYPE_NAME(int, "int")
DEFINE_TYPE_NAME(float, "float")
DEFINE_TYPE_NAME(double, "double")
DEFINE_TYPE_NAME(std::string, "string")
DEFINE_TYPE_NAME(bool, "bool")
DEFINE_TYPE_NAME(uint32_t, "uint")
DEFINE_TYPE_NAME(uint64_t, "uint")
// add your custom types' definitions
And call it like that:
void main() {
std::cout << getTypeName<int>();
}
An improvement for #Chubsdad answer,
//main.cpp
using namespace std;
int main(){
A a;
a.run();
}
//A.h
class A{
public:
A(){};
void run();
}
//A.cpp
#include <iostream>
#include <typeinfo>
void A::run(){
cout << (string)typeid(this).name();
}
Which will print:
class A*
Here is a trick for getting the name of a class you create:
struct NameTest {
NameTest() : mName {std::source_location::current().function_name()} {
}
void operator()() {
auto src_loc = std::source_location::current();
std::cout << "Class name:\t" << mName //
<< "\nFunc:\t\t" << src_loc.function_name() //
<< "\nLine:\t\t" << src_loc.line() << '\n';
}
const std::string mName;
};
int main() {
NameTest name_test;
name_test();
return 0;
}
output:
Class name: NameTest::NameTest()
Func: void NameTest::operator()()
Line: 81
A little string manipulation will strip the unneeded parts

List WPA supplicant network properties using dbus-cpp

When trying to list network properties - https://w1.fi/wpa_supplicant/devel/dbus.html#dbus_network using dbus-cpp I get a number of errors about missing operator== for core::dbus::types::Variant
/usr/include/core/dbus/impl/object.h:185:17: required from ‘std::shared_ptr<core::dbus::Property<PropertyDescription> > core::dbus::Object::get_property() [with PropertyDescription = fi::w1::wpa_supplicant1::Network::Properties::Propertiez]’ /home/martin/ClionProjects/ang-wifi-controller/src/wpasupplicantclient.cpp:149:118: required from here /usr/include/c++/6/bits/stl_pair.h:364:51: error: no match for ‘operator==’ (operand types are ‘const core::dbus::types::Variant’ and ‘const core::dbus::types::Variant’)
{ return __x.first == __y.first && __x.second == __y.second; }
My code is based on dbus-cpp examples and http://quaintous.com/2015/08/30/cpp11-dbus/, but they only offer limited assistance.
The code representing Properties property is as follows:
namespace fi {
namespace w1 {
struct wpa_supplicant1 {
struct Network {
struct Properties {
struct Propertiez {
inline static std::string name() { return "Properties"; };
typedef Network Interface;
typedef std::map<std::string, core::dbus::types::Variant> ValueType;
static const bool readable = true;
static const bool writable = true;
};
};
};
And the offending line in .cpp is networkProxy->get_property<fi::w1::wpa_supplicant1::Network::Properties::Propertiez>();
I found that this question has already been asked at https://answers.launchpad.net/ubuntu/+source/dbus-cpp/+question/593271, but nobody offered any advice. Going through the code of packages listed by apt-cache rdepends libdbus-cpp5 also yielded no results.
I tried messing with the ValueType but it all resulted in runtime errors as the expected result probably truly is the map. It honestly seems like a bug in the library to me, but since this must be an obvious use case I am trying to find the mistake in my usage of the library. So what am I doing wrong?
Edit: Since I did not get any response, I am including minimal sample.
#include <core/dbus/bus.h>
#include <core/dbus/object.h>
#include <core/dbus/property.h>
#include <core/dbus/service.h>
#include <core/dbus/result.h>
#include <core/dbus/asio/executor.h>
#include <core/dbus/interfaces/properties.h>
#include <core/dbus/types/stl/string.h>
#include <core/dbus/types/stl/tuple.h>
#include <core/dbus/types/stl/vector.h>
#include <core/dbus/types/struct.h>
#include <core/dbus/types/variant.h>
using namespace std::chrono_literals;
using DBusDict = std::map<std::string, core::dbus::types::Variant>;
namespace fi {
namespace w1 {
struct wpa_supplicant1
{
struct GetInterface {
typedef wpa_supplicant1 Interface;
static const std::string &name()
{
static const std::string s("GetInterface");
return s;
}
inline static const std::chrono::milliseconds default_timeout() { return 1s; }
};
struct Iface
{
struct AddNetwork {
typedef Iface Interface;
static const std::string &name()
{
static const std::string s("AddNetwork");
return s;
}
inline static const std::chrono::milliseconds default_timeout() { return 1s; }
};
struct Properties
{
struct Networks
{
inline static std::string name()
{ return "Networks"; };
typedef Iface Interface;
typedef std::vector<core::dbus::types::ObjectPath> ValueType;
static const bool readable = true;
static const bool writable = false;
};
};
};
struct Network
{
struct Properties
{
struct Propertiez
{
inline static std::string name()
{ return "Properties"; };
typedef Network Interface;
typedef DBusDict ValueType;
static const bool readable = true;
static const bool writable = true;
};
};
};
};
};
};
namespace core {
namespace dbus {
namespace traits {
template <> struct Service<fi::w1::wpa_supplicant1> {
inline static const std::string &interface_name()
{
static const std::string s("fi.w1.wpa_supplicant1");
return s;
}
};
template <> struct Service<fi::w1::wpa_supplicant1::Iface> {
inline static const std::string &interface_name()
{
static const std::string s("fi.w1.wpa_supplicant1.Interface");
return s;
}
};
template <> struct Service<fi::w1::wpa_supplicant1::Network> {
inline static const std::string &interface_name()
{
static const std::string s("fi.w1.wpa_supplicant1.Network");
return s;
}
};
}
}
}
int main()
{
//bus
auto systemBus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::system);
systemBus->install_executor(core::dbus::asio::make_executor(systemBus));
auto busThread = std::thread(std::bind(&core::dbus::Bus::run, systemBus));
//service
auto wpaService = core::dbus::Service::use_service<fi::w1::wpa_supplicant1>(systemBus);
auto wpaObjectPath = core::dbus::types::ObjectPath("/fi/w1/wpa_supplicant1");
auto wpaRootProxy = wpaService->object_for_path(wpaObjectPath);
//iface
auto ifacePath = wpaRootProxy->transact_method<fi::w1::wpa_supplicant1::GetInterface,
core::dbus::types::ObjectPath,
std::string>("wlan0"); //change this to your own wireless interface
auto wpaIfaceProxy = wpaService->object_for_path(ifacePath.value());
auto networkPaths = wpaIfaceProxy->get_property<fi::w1::wpa_supplicant1::Iface::Properties::Networks>();
//network
std::string ssid("network");
std::string password("password");
DBusDict args = {
{"ssid", core::dbus::types::Variant::encode(ssid)},
{"psk", core::dbus::types::Variant::encode(password)},
};
auto networkPath = wpaIfaceProxy->transact_method<fi::w1::wpa_supplicant1::Iface::AddNetwork,
core::dbus::types::ObjectPath,
DBusDict>(args);
auto networkProxy = wpaService->object_for_path(networkPath.value());
//get properties - uncomment line below to get compiler errors
//auto netProps = networkProxy->get_property<fi::w1::wpa_supplicant1::Network::Properties::Propertiez>();
while (true) {
continue;
}
}
Compile using: g++ $(pkg-config --cflags dbus-1 dbus-cpp) ./main.cpp $(pkg-config --libs dbus-1 dbus-cpp) -lpthread
Update:
dbus-cpp has an implementation for org.freedesktop.DBus.Properties.Get method.
Get:
auto resultVariant = dbus_object->invoke_method_synchronously
/*Method*/ <dbus::interfaces::Properties::Get,
/*Output Type*/ dbus::types::Variant,
/*Input Types*/ std::string, std::string>
("fi.w1.wpa_supplicant1.Network","Properties").value();
auto props = resultVariant.as<std::map<std::string, dbus::types::Variant>>();
Sadly, the Set method, while also implemented, does NOT seem to work with any ArgumentTypes with nested Variants within them. So:
a{sv} : std::map<std::string, core::dbus::types::Variant>
a{v} : std::vector<core::dbus::types::Variant>
in a Set method call will actually cause the program to crash. (Didn't test more)
Old post:
I ran into the same bug today and found a workaround for at least getting the properties value.
Instead of using
auto prop = dbus_object->get_property<fi::w1::wpa_supplicant1::Network::Properties::Propertiez>();
try
//returns std::map<std::string, core::dbus::types::Variant>>
auto props = dbus_object->get_all_properties<fi::w1::wpa_supplicant1::Network>();
auto prop = props["Properties"];
auto prop_value = prop.as<std::map<std::string, core::dbus::types::Variant>>();
As far as I understand the bug, dbus-cpp makes use of the
org.freedesktop.DBus.Properties interface to read out Properties.
So dbus_object->get_property() tries to invoke a org.freedesktop.DBus.Properties.Get and fails to compile because of the missing ==operator implementation. (Something it needs for casting the specific ValueType, I guess)
dbus_object->get_all_properties() invokes org.freedesktop.DBus.Properties.GetAll which does not need a specific ValueType, so it works.
Of course this is just a workaround to getting properties, since setting a property value is bound to the same shared_pointer as getting it.
As the documentation for fi.w1.wpa_supplicant1.Network.Properties.Properties says:
[...] All values are string type, e.g., frequency is "2437", not 2437.
So try to define DBusDict as follow:
using DBusDict = std::map<std::string, std::string>;

C++ How do you output an object's type [duplicate]

Is it possible to get the object name too?
#include<cstdio>
class one {
public:
int no_of_students;
one() { no_of_students = 0; }
void new_admission() { no_of_students++; }
};
int main() {
one A;
for(int i = 0; i < 99; i++) {
A.new_admission();
}
cout<<"class"<<[classname]<<" "<<[objectname]<<"has "
<<A.no_of_students<<" students";
}
where I can fetch the names, something like
[classname] = A.classname() = one
[objectname] = A.objectname() = A
Does C++ provide any mechanism to achieve this?
You can display the name of a variable by using the preprocessor. For instance
#include <iostream>
#define quote(x) #x
class one {};
int main(){
one A;
std::cout<<typeid(A).name()<<"\t"<< quote(A) <<"\n";
return 0;
}
outputs
3one A
on my machine. The # changes a token into a string, after preprocessing the line is
std::cout<<typeid(A).name()<<"\t"<< "A" <<"\n";
Of course if you do something like
void foo(one B){
std::cout<<typeid(B).name()<<"\t"<< quote(B) <<"\n";
}
int main(){
one A;
foo(A);
return 0;
}
you will get
3one B
as the compiler doesn't keep track of all of the variable's names.
As it happens in gcc the result of typeid().name() is the mangled class name, to get the demangled version use
#include <iostream>
#include <cxxabi.h>
#define quote(x) #x
template <typename foo,typename bar> class one{ };
int main(){
one<int,one<double, int> > A;
int status;
char * demangled = abi::__cxa_demangle(typeid(A).name(),0,0,&status);
std::cout<<demangled<<"\t"<< quote(A) <<"\n";
free(demangled);
return 0;
}
which gives me
one<int, one<double, int> > A
Other compilers may use different naming schemes.
use typeid(class).name
// illustratory code assuming all includes/namespaces etc
#include <iostream>
#include <typeinfo>
using namespace std;
struct A{};
int main(){
cout << typeid(A).name();
}
It is important to remember that this
gives an implementation defined names.
As far as I know, there is no way to get the name of the object at run time reliably e.g. 'A' in your code.
EDIT 2:
#include <typeinfo>
#include <iostream>
#include <map>
using namespace std;
struct A{
};
struct B{
};
map<const type_info*, string> m;
int main(){
m[&typeid(A)] = "A"; // Registration here
m[&typeid(B)] = "B"; // Registration here
A a;
cout << m[&typeid(a)];
}
To get class name without mangling stuff you can use func macro in constructor:
class MyClass {
const char* name;
MyClass() {
name = __func__;
}
}
Do you want [classname] to be 'one' and [objectname] to be 'A'?
If so, this is not possible. These names are only abstractions for the programmer, and aren't actually used in the binary code that is generated. You could give the class a static variable classname, which you set to 'one' and a normal variable objectname which you would assign either directly, through a method or the constructor. You can then query these methods for the class and object names.
Just write simple template:
template<typename T>
const char* getClassName(T) {
return typeid(T).name();
}
struct A {} a;
void main() {
std::cout << getClassName(a);
}
You could try using "typeid".
This doesn't work for "object" name but YOU know the object name so you'll just have to store it somewhere. The Compiler doesn't care what you namned an object.
Its worth bearing in mind, though, that the output of typeid is a compiler specific thing so even if it produces what you are after on the current platform it may not on another. This may or may not be a problem for you.
The other solution is to create some kind of template wrapper that you store the class name in. Then you need to use partial specialisation to get it to return the correct class name for you. This has the advantage of working compile time but is significantly more complex.
Edit: Being more explicit
template< typename Type > class ClassName
{
public:
static std::string name()
{
return "Unknown";
}
};
Then for each class somethign liek the following:
template<> class ClassName<MyClass>
{
public:
static std::string name()
{
return "MyClass";
}
};
Which could even be macro'd as follows:
#define DefineClassName( className ) \
\
template<> class ClassName<className> \
{ \
public: \
static std::string name() \
{ \
return #className; \
} \
}; \
Allowing you to, simply, do
DefineClassName( MyClass );
Finally to Get the class name you'd do the following:
ClassName< MyClass >::name();
Edit2: Elaborating further you'd then need to put this "DefineClassName" macro in each class you make and define a "classname" function that would call the static template function.
Edit3: And thinking about it ... Its obviously bad posting first thing in the morning as you may as well just define a member function "classname()" as follows:
std::string classname()
{
return "MyClass";
}
which can be macro'd as follows:
DefineClassName( className ) \
std::string classname() \
{ \
return #className; \
}
Then you can simply just drop
DefineClassName( MyClass );
into the class as you define it ...
You can try this:
template<typename T>
inline const char* getTypeName() {
return typeid(T).name();
}
#define DEFINE_TYPE_NAME(type, type_name) \
template<> \
inline const char* getTypeName<type>() { \
return type_name; \
}
DEFINE_TYPE_NAME(int, "int")
DEFINE_TYPE_NAME(float, "float")
DEFINE_TYPE_NAME(double, "double")
DEFINE_TYPE_NAME(std::string, "string")
DEFINE_TYPE_NAME(bool, "bool")
DEFINE_TYPE_NAME(uint32_t, "uint")
DEFINE_TYPE_NAME(uint64_t, "uint")
// add your custom types' definitions
And call it like that:
void main() {
std::cout << getTypeName<int>();
}
An improvement for #Chubsdad answer,
//main.cpp
using namespace std;
int main(){
A a;
a.run();
}
//A.h
class A{
public:
A(){};
void run();
}
//A.cpp
#include <iostream>
#include <typeinfo>
void A::run(){
cout << (string)typeid(this).name();
}
Which will print:
class A*
Here is a trick for getting the name of a class you create:
struct NameTest {
NameTest() : mName {std::source_location::current().function_name()} {
}
void operator()() {
auto src_loc = std::source_location::current();
std::cout << "Class name:\t" << mName //
<< "\nFunc:\t\t" << src_loc.function_name() //
<< "\nLine:\t\t" << src_loc.line() << '\n';
}
const std::string mName;
};
int main() {
NameTest name_test;
name_test();
return 0;
}
output:
Class name: NameTest::NameTest()
Func: void NameTest::operator()()
Line: 81
A little string manipulation will strip the unneeded parts

How to initialize stl map when they are defined as static variable as a class memebers

I am getting linker error, for the following code. I want to know how do I initialize stl map
#include <iostream>
#include <map>
#include <string>
class Test {
public:
Test() {
}
static void setSerializer(void* fnptr, std::string className) {
m_registry.insert(std::make_pair(className, fnptr));
}
static void* getSerializer(std::string className) {
return m_registry.find(className)->second;
}
private:
static std::map<std::string, void*> m_registry;
};
void fn() {
}
int main() {
Test::setSerializer(&fn,"abc");
return 0;
}
You need to define your static variable in class implementation - as you do for extern C++ variables. Just declaring it in class isn't sufficient!
To do this put the code below to the .cpp file:
std::map<std::string, void*> Test::m_registry;
You need to initialize your static member in .cpp file. Normally we declare class in .h file and put definition into .cpp file. I did a bit enhancement to your code as shown below:
Test.h
class Test
{
public:
Test() { }
static void setSerializer(std::string className, void* fnptr); // I swap the order of parameter. it makes more sense to have name and pointer pair
static void* getSerializer(std::string className);
private:
static std::map<std::string, void*> m_registry;
};
Test.cpp
std::map<std::string, void*> Test::m_registry; // initialize static member here
void Test::setSerializer(std::string className, void* fnptr)
{
m_registry.insert(std::make_pair(className, fnptr));
}
void* Test::getSerializer(std::string className) {
auto iter = m_registry.find(className); // check if iterator is valid
if (iter != m_registry.end() )
{
return (*iter).second;
}
return NULL;
}

How can I get the class name from a C++ object?

Is it possible to get the object name too?
#include<cstdio>
class one {
public:
int no_of_students;
one() { no_of_students = 0; }
void new_admission() { no_of_students++; }
};
int main() {
one A;
for(int i = 0; i < 99; i++) {
A.new_admission();
}
cout<<"class"<<[classname]<<" "<<[objectname]<<"has "
<<A.no_of_students<<" students";
}
where I can fetch the names, something like
[classname] = A.classname() = one
[objectname] = A.objectname() = A
Does C++ provide any mechanism to achieve this?
You can display the name of a variable by using the preprocessor. For instance
#include <iostream>
#define quote(x) #x
class one {};
int main(){
one A;
std::cout<<typeid(A).name()<<"\t"<< quote(A) <<"\n";
return 0;
}
outputs
3one A
on my machine. The # changes a token into a string, after preprocessing the line is
std::cout<<typeid(A).name()<<"\t"<< "A" <<"\n";
Of course if you do something like
void foo(one B){
std::cout<<typeid(B).name()<<"\t"<< quote(B) <<"\n";
}
int main(){
one A;
foo(A);
return 0;
}
you will get
3one B
as the compiler doesn't keep track of all of the variable's names.
As it happens in gcc the result of typeid().name() is the mangled class name, to get the demangled version use
#include <iostream>
#include <cxxabi.h>
#define quote(x) #x
template <typename foo,typename bar> class one{ };
int main(){
one<int,one<double, int> > A;
int status;
char * demangled = abi::__cxa_demangle(typeid(A).name(),0,0,&status);
std::cout<<demangled<<"\t"<< quote(A) <<"\n";
free(demangled);
return 0;
}
which gives me
one<int, one<double, int> > A
Other compilers may use different naming schemes.
use typeid(class).name
// illustratory code assuming all includes/namespaces etc
#include <iostream>
#include <typeinfo>
using namespace std;
struct A{};
int main(){
cout << typeid(A).name();
}
It is important to remember that this
gives an implementation defined names.
As far as I know, there is no way to get the name of the object at run time reliably e.g. 'A' in your code.
EDIT 2:
#include <typeinfo>
#include <iostream>
#include <map>
using namespace std;
struct A{
};
struct B{
};
map<const type_info*, string> m;
int main(){
m[&typeid(A)] = "A"; // Registration here
m[&typeid(B)] = "B"; // Registration here
A a;
cout << m[&typeid(a)];
}
To get class name without mangling stuff you can use func macro in constructor:
class MyClass {
const char* name;
MyClass() {
name = __func__;
}
}
Do you want [classname] to be 'one' and [objectname] to be 'A'?
If so, this is not possible. These names are only abstractions for the programmer, and aren't actually used in the binary code that is generated. You could give the class a static variable classname, which you set to 'one' and a normal variable objectname which you would assign either directly, through a method or the constructor. You can then query these methods for the class and object names.
Just write simple template:
template<typename T>
const char* getClassName(T) {
return typeid(T).name();
}
struct A {} a;
void main() {
std::cout << getClassName(a);
}
You could try using "typeid".
This doesn't work for "object" name but YOU know the object name so you'll just have to store it somewhere. The Compiler doesn't care what you namned an object.
Its worth bearing in mind, though, that the output of typeid is a compiler specific thing so even if it produces what you are after on the current platform it may not on another. This may or may not be a problem for you.
The other solution is to create some kind of template wrapper that you store the class name in. Then you need to use partial specialisation to get it to return the correct class name for you. This has the advantage of working compile time but is significantly more complex.
Edit: Being more explicit
template< typename Type > class ClassName
{
public:
static std::string name()
{
return "Unknown";
}
};
Then for each class somethign liek the following:
template<> class ClassName<MyClass>
{
public:
static std::string name()
{
return "MyClass";
}
};
Which could even be macro'd as follows:
#define DefineClassName( className ) \
\
template<> class ClassName<className> \
{ \
public: \
static std::string name() \
{ \
return #className; \
} \
}; \
Allowing you to, simply, do
DefineClassName( MyClass );
Finally to Get the class name you'd do the following:
ClassName< MyClass >::name();
Edit2: Elaborating further you'd then need to put this "DefineClassName" macro in each class you make and define a "classname" function that would call the static template function.
Edit3: And thinking about it ... Its obviously bad posting first thing in the morning as you may as well just define a member function "classname()" as follows:
std::string classname()
{
return "MyClass";
}
which can be macro'd as follows:
DefineClassName( className ) \
std::string classname() \
{ \
return #className; \
}
Then you can simply just drop
DefineClassName( MyClass );
into the class as you define it ...
You can try this:
template<typename T>
inline const char* getTypeName() {
return typeid(T).name();
}
#define DEFINE_TYPE_NAME(type, type_name) \
template<> \
inline const char* getTypeName<type>() { \
return type_name; \
}
DEFINE_TYPE_NAME(int, "int")
DEFINE_TYPE_NAME(float, "float")
DEFINE_TYPE_NAME(double, "double")
DEFINE_TYPE_NAME(std::string, "string")
DEFINE_TYPE_NAME(bool, "bool")
DEFINE_TYPE_NAME(uint32_t, "uint")
DEFINE_TYPE_NAME(uint64_t, "uint")
// add your custom types' definitions
And call it like that:
void main() {
std::cout << getTypeName<int>();
}
An improvement for #Chubsdad answer,
//main.cpp
using namespace std;
int main(){
A a;
a.run();
}
//A.h
class A{
public:
A(){};
void run();
}
//A.cpp
#include <iostream>
#include <typeinfo>
void A::run(){
cout << (string)typeid(this).name();
}
Which will print:
class A*
Here is a trick for getting the name of a class you create:
struct NameTest {
NameTest() : mName {std::source_location::current().function_name()} {
}
void operator()() {
auto src_loc = std::source_location::current();
std::cout << "Class name:\t" << mName //
<< "\nFunc:\t\t" << src_loc.function_name() //
<< "\nLine:\t\t" << src_loc.line() << '\n';
}
const std::string mName;
};
int main() {
NameTest name_test;
name_test();
return 0;
}
output:
Class name: NameTest::NameTest()
Func: void NameTest::operator()()
Line: 81
A little string manipulation will strip the unneeded parts