【问题标题】:Storing generic std::functions in a STL map?将通用 std::functions 存储在 STL 映射中?
【发布时间】:2014-09-19 07:44:39
【问题描述】:

我有一堆委托工厂,使用不同的参数定义为 Lambda,即:

std::function<Mesh*()> f1 = [&]() -> Mesh * {return new Mesh();};
std::function<Image*(const std::string&)> f2 = [&](const std::string& path) -> Image * {return new Image(path);};
std::function<VertexBuffer*(VertexBuffer::eType, int, int)> f3 = [&](VertexBuffer::eType type, int size, int count) -> VertexBuffer * {return new VertexBuffer(type, size, count);};

使用这些委托,我可以创建具有不同参数列表的不同对象类型。这些委托应由特定的 IOC 容器类处理,该类使用 std::type 作为键将它们存储在单个 STL 映射中,以确定应调用哪个委托。

我该如何存档?使用 std::function void 指针是不可能的,而我还需要为这些仿函数定义的参数。我也尝试为这些委托定义一个模板类作为工厂,但我没有找到解决方案,我如何为这个工厂定义一个接口,其中包含一个纯虚拟方法来调用委托。

template<class T, typename ... Args>
class DelegateFactory
{
public:
    std::shared_ptr<T> create(Args&& ... args) const {
        return std::shared_ptr<T>(static_cast<T*>(m_delegate(std::forward<Args>(args)...)));
    }

    void registerDelegate(std::function<T* (Args&& ... args)> delegate)
    {
        m_delegate = delegate;
    }   

private:    
    std::function<T* (Args&& ... args)> m_delegate = nullptr;
};

这看起来像是 boost::any 和 boost::any_map 的例子。但我不能使用升压。是否有一个纯基于 c++11 的解决方案来解决这个问题。或者这几乎是不可能的?

【问题讨论】:

    标签: templates c++11 lambda std-function


    【解决方案1】:

    创建一个动态存储任意委托的容器,其中每个委托可以采用任意一组参数,这在 C++ 中是不可能的。至少如果您不想删除所有类型信息(这会给您留下一个相当庞大的工厂,尤其是在没有 boost 支持的情况下)。

    但是,如果您可以使用一组静态的受支持类,则可以创建一个工厂来为这些类保存运行时分配的委托:

    template <class... Signatures>
    class DelegateFactory
    {
        // tuple storing our delegates
        typedef std::tuple<std::function<Signatures>...> tuple_type;
        tuple_type m_delegates;
    
        // helper template to check if N indexes the delegate for type T
        template<size_t N, class T> 
        using is_index_of_type = std::is_same<T*, typename std::tuple_element<N, tuple_type>::type::result_type>;
    
        // helper template go get the delegate index for type T
        template<class T>
        struct index_of_type
        {
            template <size_t N, bool IsIndex>
            struct impl
            {
                // not the correct index, try the next one
                static const size_t value = impl<N + 1, is_index_of_type<N + 1, T>::value>::value;
            };
    
            template <size_t N>
            struct impl < N, true >
            {
                // this is the correct index
                static const size_t value = N;
            };
    
            static const size_t value = impl<0, is_index_of_type<0, T>::value>::value;
        };
    
    public:
        template <class T, class F>
        void register_delegate(F functor)
        {
            // put it into the tuple
            std::get<index_of_type<T>::value>(m_delegates) = functor;
        }
    
        template <class T, class... Args>
        std::unique_ptr<T> create(Args... args)
        {
            // call the delegate with the given arguments and put the pointer into a unique_ptr
            return std::unique_ptr<T>{ std::get<index_of_type<T>::value>(m_delegates)(std::forward<Args>(args)...) };
        }
    };
    

    现场示例:http://coliru.stacked-crooked.com/a/1383d7e6670fe147

    【讨论】:

    • 感谢您的建议。我得试试看。我的问题是,我必须在容器类中使用代表。有没有办法将具有任意参数的单个委托存储为类成员,而无需模板类将此类存储在 STL 容器中?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-24
    相关资源
    最近更新 更多