2013-05-26 45 views
6

我寫了一個非常基本的表達式解析器,我希望它是可擴展的,因此它可以解析用戶定義的表達式類型。 例如,如果解析時遇到字符<,我想創建一個用於解析由此字符開始的表達式的類的實例。C++ map <char,靜態方法指針>?

我有兩個問題:

  1. 我怎麼能一個字符一個靜態方法指針聯繫起來?

    我想使用靜態方法,它將返回類的新實例,因爲我無法獲得指向類構造函數的指針。下面的語法可能是錯的,但是這想法:

    typedef static IValue * (*returnPtrIValue)(); 
    map<char, returnPtrIValue> ... 
    
  2. 假設我有A類和B類擴展類A,我可以初始化一個指向函數的指針/ REF返回到A和一個指向函數的指針,返回一個指針/ ref,因爲B是A?

    例如,我可以這樣做:

    typedef A * (*returnPtrA)(); 
    B * func() { ... } 
    returnPtrA foo = func; 
    
+0

解析是通過在所有對象之間共享的「類」方法/函數完成的,那麼您爲什麼要每次都創建一個類的新實例?只需存儲與<<相關聯的類的全局對象並使用它的方法即可。 – iammilind

+0

因爲按照我設計我的解析器的方式,表達式是一個對象,它將自己從一段字符串中解析出來。 – Virus721

+0

如果你有興趣編寫一個解析/詞法分析器,我建議看看'libclang',例如http://stackoverflow.com/questions/14509120/any-tutorial-on-libclang – user2384250

回答

2

1)只需使用的typedef刪除static,「靜態方法」就像是一個簡單的函數(只的範圍內聲明類)。

2)這似乎是合法的,但不幸的是我得到一個編譯錯誤:

error: invalid conversion from 'B* (*)()' to 'A* (*)()' 

似乎function pointers don't support covariant return types ...

+0

謝謝,我會看到如果我能以另一種方式做到這一點。 – Virus721

0

此代碼應該回答你的問題,即使不完全 。事實上,我通過使用virtual調用解決了一些問題(注意:性能問題)。

#include <iostream> 
#include <map> 


struct parse_result { 
    // something here 
}; 

class parser { 
public: 
    virtual parse_result parse() = 0; 
}; 

class parser1 : public parser { 
public: 
    parse_result parse() { 
     // something here 
     std::cout << "Called parser1::parse()" << std::endl; 
     return parse_result(); 
    } 
}; 

class parser2 : public parser { 
public: 
    parse_result parse() { 
     // something here 
     std::cout << "Called parser2::parse()" << std::endl; 
     return parse_result(); 
    } 
}; 

static parser1* make_parser1() { 
    return new parser1(); 
} 

static parser2* make_parser2() { 
    return new parser2(); 
} 

typedef parser* (*parser_factory_method)(); 


int main() { 

    std::map<char, parser_factory_method> parsers; 
    parsers.insert(std::make_pair('1', (parser_factory_method) make_parser1)); 
    parsers.insert(std::make_pair('2', (parser_factory_method) make_parser2)); 

    for (auto entry : parsers) { 
     std::cout << "Calling parser for " << entry.first << std::endl; 
     parser_factory_method pfm = entry.second; 
     parser* p = pfm(); 
     p->parse(); // parse_result is ignored here, but can be used as needed 
     delete p; 
    } 

    return 0; 

} 

請注意,我不喜歡的解析器這個設計。它以某種方式模仿Java反射,註定會遇到性能問題。看看你是否可以改進它。

+0

謝謝,我會看看如果我能適應這個我在做什麼。 – Virus721

+0

請注意,它使用了一些非重要的C++ 11功能。它可以方便地降級。 – gd1

3

1:從typedef的刪除static,如:

typedef IValue * (*returnPtrIValue)(); 

指向靜態成員函數然後可以將分配給該變量(或被放入地圖),該類型的,如:

returnPtrIValue fun = &SomeClass::somestaticfun; 

這是你要求的嗎?

2:一般來說 - 沒有。至少不是以類型安全的方式。協方差在C++中不起作用。

如果你真的要做到這一點,你可以做到這一點是任何reinterpret_cast或做一些兩輪牛車與工會,但是這可能是編譯器的依賴性,我不會建議(我可以給你一些提示,如果無論如何,你確實需要這個)。

更新:Here is the really good article,解釋瞭如何在C++中使用(成員)函數指針幫助實現C++中的委託。它深入研究了這個問題,並且我發現它的前半部分對C++中的(成員)函數指針以及如何使用它們非常好的引用/解釋。我建議檢查一下,如果你有興趣瞭解它們如何在C++中工作。

+0

謝謝,因爲1是的,這就是我需要的,爲2我會看看是否有另一種方式。 – Virus721

+0

@ Virus721酷,在這裏評論,如果你需要提示2.還可以看看我的文章更新 - 可能會變得很方便。 –

+0

謝謝,但我發現我需要在這裏:http://stackoverflow.com/questions/4007382/how-to-create-class-objects-dynamically:D – Virus721

1

如果您使用C++ 11,你可以嘗試這樣的事:

#include <map> 
#include <functional> 
... 
std::map<char, std::function<parser*()>> m; 
m['a'] = []{return new parser_for_a;}; 

這樣,你不需要有任何的靜態方法。

+0

謝謝,看起來很優雅,但我會在手機上使用它使用visual studio 2005的設備,我不確定它處理C++ 11的東西。 – Virus721

+0

是的,你至少需要vs2010。 – catscradle