2015-11-26 16 views
-1

我想编写一个类,可以监视一堆不同的值以便于调试。想象一下,在可视调试器中设置“手表”。我想像这样:C++:监视多个值类型

struct Foo { 
    int x = 0; 
    std::string s = "bar"; 
}; 

int main() { 
    Foo f; 
    ValueMonitor::watch("number", &f.x); 
    ValueMonitor::watch("string", &f.s); 
    for (int i = 0; i < 10; ++i) { 
     ++f.x; 
     if (i > 5) { 
      f.s = "new string"; 
     } 

     // print the current value of the variable with the given key 
     // these should change as the loop goes on 
     ValueMonitor::print("number"); 
     ValueMonitor::print("string"); 
     // or 
     ValueMonitor::printAll(); 

     // obviously this would be unnecessary in this example since I 
     // have easy access to f, but imagine monitoring different 
     // values from all over a much larger code base 
    } 
} 

然后,这些可以很容易地监视应用程序的GUI或任何地方的某处。

但是,我不知道如何处理将存储在这个类中的不同类型。理想情况下,我应该能够存储具有字符串表示的任何内容。我有几个想法,但没有人真的似乎是正确:

  1. 存储指向定义一个toString功能或操作< <,像Java的Object一个超类。但是这需要我为任何我想监视的基元制作包装。
  2. 类似于boost::anyboost::spirit::hold_any。我认为any需要在打印之前进行类型转换......我想我可以尝试/赶上一堆不同类型的转换,但那会很慢。 hold_any需要定义的流操作符,这将是完美的......但我无法让它与指针一起工作。

任何人有任何想法?

+0

在你的例子中,我没有看到使用'ValueMonitor'的好处。代替'ValueMonitor :: print(“number”);'你也可以拥有'std :: cout << fx << std :: endl;',效果完全一样但代码少得多 – user463035818

+0

或者你可以使用一个调试器 – user463035818

+0

是的,我的例子可能会更好。但好处是,无论应用程序的复杂程度如何,我都可以在应用程序的任何位置打印出这些值,而无需传送相关对象。想象一下像Foo这样的几十个不同的类以不同的方式嵌套,这通常比“f.x”更复杂。 – 0x5453

回答

2

我在其他地方找到了解决方案。我被吹走了,所以不妨将它张贴在这里供将来参考。它看起来像这样:

class Stringable 
{ 
public: 
    virtual ~Stringable() {}; 
    virtual std::string str() const = 0; 

    using Ptr = std::shared_ptr<Stringable>; 
}; 

template <typename T> 
class StringableRef : public Stringable 
{ 
private: 
    T* _ptr; 

public: 
    StringableRef(T& ref) 
     : _ptr(&ref) {} 
    virtual ~StringableRef() {} 

    virtual std::string str() const 
    { 
     std::ostringstream ss; 
     ss << *_ptr; 
     return ss.str(); 
    } 
}; 

class ValueMonitor 
{ 
private: 
    static std::map<std::string, Stringable::Ptr> _values; 

public: 
    ValueMonitor() {} 
    ~ValueMonitor() {} 

    template <typename T> 
    static void watch(const std::string& label, T& ref) 
    { 
     _values[label] = std::make_shared<StringableRef<T>>(ref); 
    } 

    static void printAll() 
    { 
     for (const auto& valueItr : _values) 
     { 
      const String& name = valueItr.first; 
      const std::shared_ptr<Stringable>& value = valueItr.second; 
      std::cout << name << ": " << value->str() << std::endl; 
     } 
    } 

    static void clear() 
    { 
     _values.clear(); 
    } 
}; 

std::map<std::string, Stringable::Ptr> ValueMonitor::_values; 

int main() 
{ 
    int i = 5; 
    std::string s = "test" 
    ValueMonitor::watch("number", i); 
    ValueMonitor::watch("string", s); 
    ValueMonitor::printAll(); 

    i = 10; 
    s = "new string"; 
    ValueMonitor::printAll(); 

    return 0; 
}