2016-01-24 25 views
1

我試圖做出將舉行對象及其位置的通用容器:如何存儲一個函數對象而不訴諸於std :: function?

class Vector; 

template <typename T> 
class Container 
{ 
public: 
    void insert(const T& t) 
    { 
     insertAtPosition(t.getPosition() ,t); 
    } 
private: 
    void insertAtPosition(const Vector& v, const T& t); 
    ... 
} ; 

但是,如果用戶的目標位置,吸不叫getPosition

如何使這個容器通用於容器內部獲取物品位置的方式?

到目前爲止,我已經考慮3種方法,他們都不理想:

  1. 一個std::function<const Vector& (const T& t)>成員添加到Container

這是一個乾淨的C++解決方案,但是這個函數將被非常頻繁地調用,並且可能會導致性能明顯下降。

  • 添加函子對象到容器:

    class Vector; 
    
    template <typename T, typename TGetPosition> 
    class Container 
    { 
    public: 
        Container(TGetPosition getPosition): getPosition_(getPosition){} 
    
        void insert(const T& t) 
        { 
         insertAtPosition(getPosition_(t) ,t); 
        } 
    private: 
        void insertAtPosition(const Vector& v, const T& t); 
        TGetPosition getPosition_; 
    } ; 
    
  • 我可以使用object generator idiom,使其能夠使用lambda表達式:

    template <typename T, typename TGetPosition> 
    Container<T, TGetPosition> makeContainer(TGetPosition getter) 
    { 
        return Container<T, TGetPosition>(getter); 
    } 
    
    ... 
    
    auto container = makeSimpleContainer<Widget>([](const Widget& w) 
        { 
         return w.tellMeWhereYourPositionMightBe(); 
        }); 
    

    不會有性能開銷,但在某些情況下獲取這種容器的類型是不可能的。例如,您無法創建一個將此類容器作爲參數的類,因爲decltype不起作用,因爲lambda不能用於未評估的上下文中。

    1. 使用#define GETTER getPosition,用戶只需將getPosition更改爲任何他喜歡的。這種方法有很多錯誤,我甚至不知道從哪裏開始。

    請問,有沒有其他方法可以做到這一點?我錯過了什麼?任何指導是最受歡迎的!

    編輯:

    關於解決方案2:我不知道我們如何能夠得到一個lambda函數創建一個容器的類型。一種方法是:

    using TContainer = decltype(makeSimpleContainer<Widget>([](const Widget& w) 
        { 
         return w.tellMeWhereYourPositionMightBe(); 
        });) 
    

    但是這不起作用,因爲lambda不能用在未評估的上下文中。

    +0

    你是說't.getPosition()'返回一個向量? –

    +0

    你能否舉一個你描述的'decltype'問題的例子,因爲它涉及到你的問題? –

    +0

    @KerrekSB是的,正好。 T有一個隱含的接口。 –

    回答

    1

    合理的可用選項將是預期的背景下有position_for()

    template <class T> struct Container { 
        size_t insert(T const& x) { 
         insertAtPosition(position_for(x), x); 
        } 
    }; 
    
    Vector const& position_for(const Widget& w) { 
        return ...; 
    } 
    
    Container<Widget> c; 
    c.insert(Widget()); 
    

    ...但其中容器產生從業務對象鍵的設計通常不靠譜的好,因爲來查找一個對象將需要做一個虛擬的,這可能是昂貴的。

    1

    好像即使你需要做一個類保持容器你的第二個解決方案將工作:

    template <typename Container> 
    struct SomeClass { 
        SomeClass(const Container &container) : container(container) { } 
        Container container; 
    }; 
    
    
    int main() 
    { 
        auto container = makeSimpleContainer<Widget>([](const Widget& w) 
         { 
          return w.tellMeWhereYourPositionMightBe(); 
         }); 
        SomeClass<decltype(container)> test(container); 
    } 
    
    相關問題