2017-09-21 26 views
1

有時我在解析器之間有緊密的耦合/循環依賴關係。我可能有這樣的事情:依賴注入使用X3的解析器

parser.hpp

#pragma once 

namespace parser { 
    using a_type = x3::rule<class a_class>; 
    a_type const a = "a"; 

    using b_type = x3::rule<class b_class>; 
    b_type const b = "b"; 

    auto const a_def = "(" >> b >> ")"; 
    auto const b_def = "<" >> a >> ">"; 

    BOOST_SPIRIT_DEFINE(a, b); 
} 

不過,我想這些分成不同的標題,因爲這將能使用於較小的編譯時間,當我的單元測試和具有多頭文件(而不是一個單片文件)。事實上,我擁有的不僅僅是2個解析器。

我希望能夠做這樣的事情:

a.hpp

#pragma once 

#include "b.hpp" 

namespace parser { 
    using a_type = x3::rule<class a_class>; 
    a_type const a = "a"; 
    auto const a_def = "(" >> b_wrapper<a>::b >> ")"; 

    BOOST_SPIRIT_DEFINE(a); 
} 

b.hpp

#pragma once 

namespace parser { 
    template <auto Injected> 
    struct b_wrapper { 
     using b_type = x3::rule<class b_class>; 
     static b_type const b = "b"; 
     static auto const b_def = "(" >> Injected >> ")"; 

     BOOST_SPIRIT_DEFINE(b); 
    }; 
} 

當然,這也不行。我如何實現解析器的依賴注入?


我不關心注射的確切語法。可是,我真的需要這些點:

  • 能夠測試a.hppb.hpp沒有包括在這兩個測試文件都頭(a可以很容易地製作成具有的依賴注入太)
  • 能夠替代注入分析器與另一解析器來緩解測試

我沒事,如果我有我每次注入不同的解析器時間有一堆的樣板。

回答

0

您可以通過函數生成您的foo_def對象。也就是說,b.hpp應該是這樣的:

#pragma once 

namespace parser { 
    template <typename Injected> 
    auto b_impl(Injected const& injected) { 
     return "(" >> injected >> ")"; 
    } 
} 

而且要注入的實際解析器,你可以這樣做:

using b_type = x3::rule<class b_class>; 
b_type const b = "b"; 
auto const b_def = b_impl(a); 

BOOST_SPIRIT_DEFINE(b); 

注意,還有樣板該位當你想創建解析器時。