I want to print variables of many types. I've made a class named IStringable
, and some classes that derive from it. In my PrintVariable
function I want to check whether the parameter derives from IStringable
, and if it does then print it.
class IStringable {
public:
virtual ~IStringable() { }
virtual std::string ToString() const = 0;
}
class Person : public IStringable {
public:
Person(const std::string name) : _name(name) { }
virtual std::string ToString() const { return _name; }
private:
std::string _name;
}
// This does not work as intended, as I don't know how it could be implemented
template <>
void PrintVariable<IStringable>(const IStringable& var) {
std::cout << var.ToString() << std::endl;
}
int main() {
Person p("Foo");
PrintVariable(p);
}
So far I've worked around this problem by just using std::cout << p.ToString() << std::endl;
instead, but I'm wondering if there's a better solution to this.
The isinstance() function checks if the object (first argument) is an instance or subclass of the class info class (second argument).
Use class_name dot variable_name to access a class variable from a class method in Python. Use instance to access variables outside the class.
isinstance() checks whether or not the object is an instance or subclass of the classinfo.
C++ has no direct method to check one object is an instance of some class type or not. In Java, we can get this kind of facility. In C++11, we can find one item called is_base_of<Base, T>. This will check if the given class is a base of the given object or not.
You don't need a template:
void PrintVariable(const IStringable& var) {
std::cout << var.ToString() << '\n';
}
Only calls to PrintVariable
with object convertible to IStringable
are legal:
Person p("Alice");
struct Bob {} b;
PrintVariable(p); // OK
PrintVariable(b); // ill-formed: no conversion from Bob to const IStringable&
Additionally, you could redesign PrintVariable
as an operator:
std::ostream& operator<<(std::ostream& os, IStringable const& rhs)
{
return os << rhs.ToString();
}
So you could write:
Person p("Alice");
std::cout << p << '\n';
As it appears from comments, OP whants a way to log things. A minimal implementation would be:
#include <string_view>
#include <type_traits>
#include <iostream>
namespace Logger
{
struct IStringable
{
virtual ~IStringable() {}
virtual std::string ToString() const = 0;
};
std::string to_string(IStringable const& v) { return v.ToString(); }
void log(std::string_view const& sv)
{
std::cout << "debug: " << sv << '\n';
}
template<class T, std::enable_if_t<!std::is_convertible_v<T, std::string_view>, int> = 0>
void log(T const& v)
{
using std::to_string;
log(to_string(v));
}
}
The idea is to use ADL and SFINAE to call either std::to_string
or ISrtingable::ToString
on the thing to log, and log the resultant string.
Usage:
class Person : public Logger::IStringable {
public:
Person(const std::string name) : _name(name) { }
virtual std::string ToString() const { return _name; }
private:
std::string _name;
};
int main()
{
Person p("Alice");
double d = 0.0;
const char* c = "Some words";
Logger::log(p);
Logger::log(d);
Logger::log(c);
}
Demo: https://coliru.stacked-crooked.com/a/77e19e87c9d4780d
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With