我想打印许多类型的变量。我已经创建了一个名为IStringable
的类,并且派生了一些类。在我的PrintVariable
函数中,我想检查参数是否源自IStringable
,如果确实要打印该参数。
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);
}
到目前为止,我只是通过使用std::cout << p.ToString() << std::endl;
来解决此问题,但我想知道是否有更好的解决方案。
答案 0 :(得分:8)
您不需要模板:
void PrintVariable(const IStringable& var) {
std::cout << var.ToString() << '\n';
}
仅调用对象可转换为PrintVariable
的{{1}}是合法的:
IStringable
此外,您可以将Person p("Alice");
struct Bob {} b;
PrintVariable(p); // OK
PrintVariable(b); // ill-formed: no conversion from Bob to const IStringable&
重新设计为运算符:
PrintVariable
所以你可以这样写:
std::ostream& operator<<(std::ostream& os, IStringable const& rhs)
{
return os << rhs.ToString();
}
从评论中可以看出,OP希望记录事件。最小的实现是:
Person p("Alice");
std::cout << p << '\n';
想法是使用ADL和SFINAE在要记录的事物上调用#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));
}
}
或std::to_string
,并记录生成的字符串。
用法:
ISrtingable::ToString