2013-04-30 49 views
7

這是我進入這個偉大的知識交流的第一個問題,我希望我能找到一些幫助。如何迭代boost :: fusion關聯結構並以通用方式訪問關鍵字

我嘗試實現一種通用的方式來創建PrintTo函數(稍後將在GoogleTest中使用)。

所以下面的代碼只做了一半的工作。它只打印定義的結構Foo::Bar

#include <iostream> 
#include <sstream> 
#include <string> 

#include <boost/fusion/container.hpp> 
#include <boost/fusion/algorithm.hpp> 
#include <boost/fusion/adapted/struct/define_assoc_struct.hpp> 
#include <boost/fusion/include/define_assoc_struct.hpp> 

namespace Foo 
{ 
    namespace Keys 
    { 
    struct StringField; 
    struct IntField; 
    }; 
} 

BOOST_FUSION_DEFINE_ASSOC_STRUCT(
    (Foo), Bar, 
    (std::string, stringField, Foo::Keys::StringField) 
    (int,   intField, Foo::Keys::IntField)) 


struct fusion_printer_impl 
{ 
    std::ostream& _os; 

    fusion_printer_impl(std::ostream& os) 
    : _os(os) {} 

    template <typename T> 
    void operator() (T& v) const 
    { 
    _os << v << std::endl; 
    } 
}; 

void PrintTo(Foo::Bar const& v, std::ostream* os) 
{ 
    boost::fusion::for_each(v, fusion_printer_impl(*os)); 
} 

int main() 
{ 
    Foo::Bar fb("Don't panic!", 42); 
    std::ostringstream temp; 

    PrintTo(fb, &temp); 

    std::cout << temp.str() << std::endl; 
} 

的值那麼我期待的是自動打印Foo::Keys還有一種方式。我查看了makro生成的BOOST_FUSION_DEFINE_ASSOC_STRUCT代碼,並且據我所見,Keys可以用作靜態常量char * boost :: fusion :: extension :: struct_member_name :: call()。

我查看了fusion :: for_each的代碼,到目前爲止,我只看到一種方法來「複製」完整代碼,以便用兩個參數Key和values調用fusion_printer_impl :: operator()。在我進入這個方向之前,我想知道是否有更簡單的方法來實現這一點。

我知道可以定義顯式的boost :: fusion :: map。這裏可以通過fusion :: pair自動訪問Key類型和值。但是,這對我來說目前不適合。

所以這裏的任何幫助是受歡迎的。

回答

2

你是一個很好的問題,希望這裏有人會來的東西比這更清潔:

... 
struct fusion_printer_2 
{ 
    typedef std::ostream* result_type; 

    // Well, not really the intented use but... 
    template<typename T> 
    std::ostream* operator()(std::ostream const* out, const T& t) const 
    { 
     std::ostream* const_violated_out = const_cast<result_type>(out); 
     (*const_violated_out) << 
      (std::string(typeid(typename boost::fusion::result_of::key_of<T>::type).name()) + ": " + boost::lexical_cast<std::string>(deref(t))) << std::endl; 
     return const_violated_out; 
    } 
}; 

void PrintTo(Foo::Bar const& v, std::ostream* os) 
{ 
    boost::fusion::iter_fold(v, os, fusion_printer_2()); 
} 
... 
+1

感謝您的回答。它幫助我進一步。通過將函數的result_type更改爲std :: string並將boost :: fusion :: iter_fold的結果直接傳遞給* os,我可以避免使用_ugly_ const_cast。 – 2013-04-30 16:28:12

+0

甚至不要提到它,留下一個人讓他的靈魂被深不可測的抽象和沉重的編譯錯誤壓垮會是非常不人道的...... – dsign 2013-04-30 18:57:50

+0

我知道你在說什麼。至少VC10和Clang已經改善了很多。 (我不知道gcc)。在boost :: spirit的使用中出現錯誤總是很有趣:-( – 2013-04-30 20:59:35