【问题标题】:print any struct in template function在模板函数中打印任何结构
【发布时间】:2018-02-13 13:17:56
【问题描述】:

我有 3 个或更多 struct ,并且我希望我有一个打印任何 struct 的函数

例如:

struct A 
{
  int a0;
  string a1;
  bool a2;
}

struct B
{
 CString b0;
 double b1;
 int b2;
 string b3
}

我想用相同的功能打印这个结构(A和B)

像这样:

template<typename T>
inline void print(T)
{
  std::cout << // I don't know what is write here....
}

有人帮我吗?

【问题讨论】:

  • 您希望print 函数如何知道如何 打印内容? C++ 没有反射(还)
  • 四处寻找反射。不幸的是,C++ 本身(还)没有它,但是有一些库实现,例如 Boost.Fusion,它可以在一些用户帮助下生成必要的元数据。
  • 您只是想使用相同的名称或printing,还是希望函数像 UnholySheep 询问的那样预测结构的内容?
  • @Quentin 你能解释一下反射吗?这是什么?

标签: c++ templates struct


【解决方案1】:

C++ 中的通常做法是为您的类型定义operator&lt;&lt;(std::ostream &amp;, const T &amp;)

std::ostream &operator<<(std::ostream &os, const A &value)
{
    // print here
    return os;
}

这应该针对您要打印的每种类型完成,并且该函数应该定义在与该类型相同的命名空间中。

之后,您的数据类型可以打印到所有输出流。这也允许像 boost::lexical_cast 这样的东西与您的类型一起使用,因为它在内部将值打印到 std::stringstream

【讨论】:

  • @Joo 手动为每种数据类型。询问如何遍历所有字段?因为我没有看到问题中提到了这一点。
  • @Joo 如果您确实需要打印它(例如,需要它来调试或记录),那么我强烈建议您手动执行此操作。自定义打印可能比自动生成的内容更有用。
【解决方案2】:

另外,另一种解决方案是例如制作一个名为to_string的函数(这是直接将你的结构转换为字符串,但性能不好)

struct A
{
  int a0;
  string a1;
  bool a2;

  string to_string() const {
      return "{ " + std::to_string(a0) + ", " + a1 + ", " + (a2 ? "true" : "false") + " }";
  }
};

然后

template<typename T>
void print(const T &a) {
    cout << a.to_string() << "\n";
}

这对打印不好,对于打印,使用实现operator&lt;&lt;的C++约定

但是。

这有一个缺点,当子类想要改变输出格式时。不能。

所以

class DynamicallyToStringConvertible {
public:
    virtual string to_string() const = 0;
    virtual ~DynamicallyToStringConvertible() {}
};

struct A: DynamicallyToStringConvertible
{
    ...
    virtual string to_string() const {
        return "{ " + std::to_string(a0) + ", " + a1 + ", " + (a2 ? "true" : "false") + " }";
    }
}

struct SubclassFromA: public A {
    virtual string to_string() const {
        return "Subclass: " + A::to_string();
    }
};

函数print原样

然后

void tryPrintingAsA(const A &a) {
    print(a);
}

您现在会发现(在虚函数之后),这将适用于 SubclassA。 但是,如果您尝试了 operator&lt;&lt; 或解决方案的开头(没有虚拟的 to_string),它将适用于 SubclassA,因为它是普通 A。

然后你会做这样的事情

friend ostream &operator<<(ostream &s, const DynamicallyToStringConvertible &p) {
    return s << p.to_string();
}

在您的 Base 类中,如下所示:

class DynamicallyToStringConvertible {
public:
    virtual string to_string() const = 0;
    virtual ~DynamicallyToStringConvertible() {}

    friend ostream &operator<<(ostream &s, const DynamicallyToStringConvertible &p) {
        return s << p.to_string();
    }
};

现在试试 A 的打印函数是:

void tryPrintingAsA(const A &a) {
    cout << a;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-09
    • 2016-11-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多