2014-10-16 53 views
3

我試圖在語法的繼承參數中傳遞語義動作。Boost :: spirit在繼承屬性中傳遞語義動作

在下面這個非常基本的例子中,語法分析兩個數字,並且將語義動作(以C++ lambda的形式)傳遞給它,我希望在解析第一個數字時調用該動作。然而,它並沒有被調用,而是被默默地忽略了,我想知道爲什麼這樣做,以及做這種事情的正確方法是什麼。

#include <iostream> 
#include <boost/spirit/include/qi.hpp> 

using namespace std; 
using namespace boost; 

namespace qi = spirit::qi; 
namespace phx = phoenix; 

template <typename Iterator, typename Action> 
struct two_numbers : qi::grammar<Iterator, void (Action const&)> 
{ 
    two_numbers() : two_numbers::base_type(start) 
    { 
    using namespace qi; 
    start = int_ [ _r1 ] >> ' ' >> int_; 
    } 
    qi::rule<Iterator, void (Action const&)> start; 
}; 

int main() 
{ 
    string input { "42 21" }; 
    auto first=std::begin (input), last=std::end(input); 

    static const auto my_action = [] (auto&& p) { 
    cout << "the meaning of life is " << p << "\n"; 
    }; 

    static const two_numbers <decltype(first), decltype (my_action)> p; 

    if (qi::parse (first, last, p(phx::ref(my_action)))) 
    cout << "parse ok\n"; 
} 

預期輸出是:

the meaning of life is 42 
parse ok 

而真正的輸出是:

parse ok 
+0

強制鏈接:[Boost Spirit:「語義動作是邪惡的嗎?」](http://stackoverflow.com/questions/8259440/boost-spirit-semantic-actions-are -vil) – sehe 2014-10-16 22:28:07

回答

4

首先,立即迴應:

「我想通過語法的繼承論證來傳遞語義行爲。「

即時創傷性休克。你......你......什麼?

C++對於高階編程並不是很好,當然不是基於表達式模板的靜態多態。事實上,它是,但在我以前的回答中,我已經告誡不要將UB存儲在命名對象(變量)中的表達式模板。

那個時候你發現了UB。在我看來,這是幸運的。

最近,我已經遇到的另一個問題有關類似的目標:

要特別注意評論跟帖。我不認爲這是一條理智的道路,至少直到Boost Mpl完成了C++ 11的完整性(Boost Hana,或許?)和Proto-0x被髮布之後。

到那時,Spirit X3可能已經成熟了,我們只剩下Boost Phoenix的差距了。我不確定這是否是任何人的議程。

簡而言之:我們會被困在這個「中途」的土地上,我們可以擁有美好的事物,但有一些相當有限的限制。我們應該避免被帶走,假裝我們突然能夠用C++編寫Haskell。

也相關:有一個建議(N4221, pdf)用於C++中的參考文獻的通用生命週期擴展。它提供了一些簡單的應用程序,例如Boost Range適配器的一些很好的例子,這些適配器在當前的C++中靜靜地UB。例如。從§2開始。3環球觀察:

std::vector<int> vec; 
for (int val : vec | boost::adaptors::reversed 
        | boost::adaptors::uniqued) 
{ 
     // Error: result of (vec | boost::adaptors::reversed) died. 
} 

解決方案

這就是說,由於繼承的說法將是一個仿函數(不是一個懶惰的演員),你需要將其綁定:

start = int_ [ phx::bind(phx::cref(_r1), qi::_1) ] >> ' ' >> int_; 

這確實有效:Live On Coliru

Howev呃,我不推薦這個

+0

添加了N4221建議的鏈接(謝謝@AndyProwl) – sehe 2014-10-16 22:40:26

+0

謝謝你的回答。我修改我的例子,現在通過懶的演員,但預期它仍不能工作:[COLIRU鏈接](http://coliru.stacked-crooked.com/a/7790ff05a15f234c)此外,如果不確定的行爲發生的,因爲早期銷燬prvalue和懸掛參考,你能在代碼中準確顯示問題的參考嗎? – 2014-10-17 06:26:29

+0

@NikkiChumakov我不能(目前)。我可能不會找到動機。然而,在Boost Phoenix中**有一些東西,它告訴Phoenix表達式模板是否是「無狀態的」(也許我記得當表達式的類型是default-constructible?時,這種情況就是這種情況)。如果是這樣的話,那麼存儲它就沒有問題了。否則,所有投注都關閉。 Eric Niebler本人詳細介紹了這一職位,IIRC。 – sehe 2014-10-17 06:35:38