2015-11-26 26 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; 
}