2014-11-21 52 views
2

我一直在學習boost :: spirit,並且遇到了語法動作在語法構造過程中被評估的混淆。下面的代碼產生輸出:在語法構造函數中評估的語義動作(或不是?)

string= 

我的假設是,該輸出作爲語義動作的一部分附接至orule

有沒有辦法避免這種行爲?或者如果我在語義動作中使用std::cout,我會需要忍受嗎?

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

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

template <typename Iterator> 
    struct my_grammar : qi::grammar<Iterator, std::string() > 
{ 
    my_grammar() : my_grammar::base_type(orule) 
    { 
     using qi::_1; 
     using qi::_2; 
     using qi::attr; 
     using qi::string; 
     using phx::val; 

     orule = string("abc") [ std::cout << "string=" << _1 << std::endl ]; 
    } 
    qi::rule< Iterator, std::string() > orule; 
}; 

int main() 
{ 
    typedef std::string::const_iterator iterator_type; 
    typedef my_grammar<iterator_type> parser; 
    parser my_parser; // Our grammar 
    return 0; 
} 

回答

3

簡短的回答:不,語義動作是規則初始化過程中不評估。

但是,你的問題是你沒有(只)寫一個語義動作。


是的,在你的情況下表達

std::cout << "string=" << _1 << std::endl 

的第一部分具有一個副作用:(std::cout << "string=")插入文字轉換成標準的ostream對象和然後返回std::cout通過引用。

這是因爲您使用標準庫中定義的std::operator<<而不是boost::phoenix::....::operator<<¹。


您可以通過迫使解決這個問題的第二個參數的東西的類型,將選擇合適的過載:

std::cout << phx::val("string=") << _1 << std::endl 

當然,你總是可以通過例如做以防萬一

phx::ref(std::cout) << _1 << std::endl 

但是你會注意到,只要有可能,人們往往會跳過這一點。第二個操作數是boost::spirit::_1已經誘導了表達式模板上下文(即選擇構造懶惰actor的非標準操作符重載而不是副作用)。


¹這可能最終只是被boost::proto::....::operator<<無論如何,但這是所有美味的實施細則:)

+0

謝謝您的回答 - 這給了我進一步洞察到這些語義動作實際上是怎麼回事 – Jimmy 2014-11-21 22:15:56

相關問題