使用指向部分专用函数成员的指针自动填充向量 [英] Fill a vector with pointers to partially specialized function members automatically

查看:173
本文介绍了使用指向部分专用函数成员的指针自动填充向量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个类似管道的设计模式。我的一个设计目标是通过提供指向某个数据类的函数成员的指针来实现流水线段的动态链接。

I am working on a pipeline-like design pattern. One of my design goals is to enable dynamic linking of pipeline segments by providing pointers to function members of a certain data class.

每个数据类都有一组函数成员(表示数据类输出端口),使用整数模板参数进行索引。这些函数使用 auto 关键字动态地推导返回类型,但都接受相同的整数参数 c_Idx ,即 template< int N> auto getOutput(int c_Idx)const 。与每个函数 getOutput 相关联的功能由一组部分专用结构 getOutputImpl 定义(由用户定义)。因此,每个数据类可以具有从1到某些固定数 K 的输出数据端口。

Each of the data classes has a set of function members (representing the data class output ports) indexed using an integer template argument. These functions deduce the return type dynamically using the auto keyword, but all accept the same integer argument c_Idx, i.e. template <int N> auto getOutput(int c_Idx) const. The functionality associated with each function getOutput is defined (by the user) in a set of partially specialised structures getOutputImpl. Thus, each data class can have from 1 up to some fixed number K of output data ports.

为了允许以通用方式在管线段之间动态链接,它们可以存储在 std :: vector& boost ::任何> 容器。但是,我需要能够自动填充这个向量与函数成员模板的指针。

In order to allow for dynamic linking between the pipeline segments in a generic manner they can be stored in a std::vector<boost::any> container. However, I need to be able to fill this vector with pointers to the function member templates automatically.

手动实现的示例如下所示

An example of a manual implementation is shown below

template<class TLeafType>
class AlgorithmOutput
{

protected:

    std::vector<boost::any> OutputPorts;

public:

    AlgorithmOutput()
        {

            //////////////////////////////////////////
            // This procedure needs to be automated //
            //////////////////////////////////////////
            std::function<std::unique_ptr<double>(int)> pOutFun1 = std::bind(
                std::mem_fn(
                    true ? &AlgorithmOutput<TLeafType>::getOutput<0> : nullptr
                    ),
                this,
                std::placeholders::_1
                );
            OutputPorts.push_back(pOutFun1);

            std::function<std::unique_ptr<int>(int)> pOutFun2 = std::bind(
                std::mem_fn(
                    true ? &AlgorithmOutput<TLeafType>::getOutput<1> : nullptr
                    ),
                this,
                std::placeholders::_1
                );
            OutputPorts.push_back(pOutFun2);

        }

    virtual ~AlgorithmOutput() {}

protected:

    TLeafType* asLeaf(void)
        {
            return static_cast<TLeafType*>(this);
        }

    TLeafType const* asLeaf(void) const
        {
            return static_cast<TLeafType const*>(this);
        }

public:

    template <int N>
    auto getOutput(int c_Idx) const
        {
            return asLeaf() -> getOutput<N>(c_Idx);
        }

    boost::any getOutputPort(int PortIdx)
        {
            return OutputPorts[PortIdx];
        }

};

class PipeOutputClass: public AlgorithmOutput<PipeOutputClass>
{

public:

    template <int N>
    auto getOutput(int c_Idx) const
        {
            return getOutputImpl<N>::apply(this, c_Idx);
        }

    template<int N, typename S> friend struct getOutputImpl;

    template<int N, typename = void>
    struct getOutputImpl
    {
        static auto apply(
            PipeOutputClass const* p_Self,
            int c_Idx
            )
            { throw std::runtime_error("Wrong template argument."); }
    };

    template <typename S>
    struct getOutputImpl<0, S>
    {
        static std::unique_ptr<double> apply(
            PipeOutputClass const* p_Self,
            int c_Idx
            )
            {
                std::unique_ptr<double> mydouble(new double(10));
                return mydouble;
            }
    };

    template <typename S>
    struct getOutputImpl<1, S>
    {
        static std::unique_ptr<int > apply(
            PipeOutputClass const* p_Self,
            int c_Idx
            )
            {
                std::unique_ptr<int > myint(new int(3));
                return myint;
            }
    };

};

上面的例子的问题是我定义了成员函数指针 pOutFunX

The problem with the example above is that I define the member function pointers pOutFunX manually, whereas I would like to automate this procedure.

请注意,我不考虑与上述设计有明显差异的设计解决方案。

Please note that I am not considering design solutions which differ significantly from the design specified above.

这里我介绍一些解决这个问题的可能方法的想法。我为目前正在考虑的解决方案制定了一个计划,如果您试图回答这个问题,可能会有用:

Here I present some thoughts on some of the possible approaches for solving this problem. I developed a plan for a solution that I am currently considering, which may be of use if you attempt to answer this question:


  1. 获取对于每个这样的结构,确定其成员名为<$ c的输出类型。

  2. < $ c> apply

  3. 设置(递归)元模板过程,创建指向相关签名函数的指针,并将它们添加到 OutputPort 向量。

  1. Obtain the number of the user defined partially specialised structures named getOutputImpl.
  2. For each such structure determine the output type of its member named apply.
  3. Set up a (recursive) meta-template procedure that creates pointers to functions with the relevant signature and adds them to the OutputPort vector.

我假设上面的步骤1-3都将在编译时完成。我不关心解决方案的美观,如果它不需要用户设计数据输出类的任何干预。但是,我不想使用自定义编译器宏。

I would assume that the steps 1-3 above will all have to be done at compile time. I am not concerned about the aesthetics of the solution, if it does not require any intervention from the user designing the data output classes. However, I would prefer not to use custom compiler macros.

此帖显示如何,这可能是有用的。

This post shows how one can infer a member function signature, which may be useful.

推荐答案

我要感谢所有发表他们的回答的人。不幸的是,没有一个答案工作开箱即用,当我开始尝试改进它们时,我对可变参数模板和C ++ 11/14标准的相关功能了解有限。因此,我开发了自己的解决方案,你可以在下面找到。解决方案是松散地基于问题和Columbo的答案中提出的计划。特别是,我使用稍微修改版本的 getK 函数在Columbo的答案中提出。我也使用你的想法使用 std :: index_sequence 在编译时生成向量。但是,我的实现有些不同。

I would like to thank everyone who posted their answers for their input. Unfortunately, none of the answers worked 'out of the box' and when I started trying to improve them I had a limited understanding of variadic templates and associated features of the C++11/14 standard. Thus, I developed my own solution, which you can find below. The solution is loosely based on the plan proposed in the question and Columbo's answer. In particular, I used slightly modified versions of the getK function proposed in Columbo's answer and. I have also used your idea to use std::index_sequence for generation of the vector at compile time. However, my implementation is somewhat different.

我相信我的解决方案远远不是最优的。因此,如果您对如何改进它有任何想法,我将非常感谢您的进一步的投入。

I believe that my solution is far from optimal. Thus, if you have any ideas about how I can improve it, I will highly appreciate your further input.

template<class TLeafType>
class AlgorithmOutput
{

private:

    typedef AlgorithmOutput<TLeafType> AO;

protected:

    std::vector<boost::any> OutputPorts;

public:

    AlgorithmOutput()
        {
            OutputPorts = this -> getOutputPorts();
        }

    virtual ~AlgorithmOutput() {}

    template<std::size_t... I>
    auto genOutputPortsImpl(std::index_sequence<I...>)
        {
            return std::vector<boost::any>(
                {boost::any(
                        static_cast<
                        std::function<decltype(AO::getOutput<I>(0))(size_t)>
                        >(std::bind(
                              std::mem_fn(true ? &AO::getOutput<I> : nullptr),
                              this,
                              std::placeholders::_1
                              )
                            )
                        )...}
                );
        }

    template<std::size_t N, typename Indices = std::make_index_sequence<N>>
        auto genOutputPorts()
        { return genOutputPortsImpl(Indices()); }

    std::vector<boost::any> getOutputPorts(void)
        {
            return std::vector<boost::any>(
                genOutputPorts<this -> getOutputPortsNumber()>()
                );
        }

protected:

    TLeafType* asLeaf(void)
        { return static_cast<TLeafType*>(this); }

    TLeafType const* asLeaf(void) const
        { return static_cast<TLeafType const*>(this); }

public:

    template <size_t N>
    auto getOutput(size_t c_Idx) const
        {
            return asLeaf() -> getOutput<N>(c_Idx);
        }

    boost::any getOutputPort(int PortIdx)
        { return OutputPorts[PortIdx]; }

    template<size_t N>
    static constexpr std::enable_if_t<
        std::is_void<
            decltype(std::declval<TLeafType*>() -> getOutput<N>(0))>::value,
            size_t
            > getOutputPortsNumberImpl()
        { return N; }

    template<size_t N>
    static constexpr std::enable_if_t<
        !std::is_void<
            decltype(std::declval<TLeafType*>() -> getOutput<N>(0))>::value,
            size_t
            > getOutputPortsNumberImpl()
        { return getOutputPortsNumberImpl<N + 1>(); }

    static constexpr size_t getOutputPortsNumber(void)
        { return getOutputPortsNumberImpl<0>(); }

};

class PipeOutputClass: public AlgorithmOutput<PipeOutputClass>
{

public:

    template <size_t N>
    auto getOutput(size_t c_Idx) const
        {
            return getOutputImpl<N>::apply(this, c_Idx);
        }

    template<size_t N, typename S> friend struct getOutputImpl;

    template<size_t N, typename = void>
    struct getOutputImpl
    {
        static auto apply(
            PipeOutputClass const* p_Self,
            size_t c_Idx
            )
            {
                throw std::runtime_error("Wrong template argument.");
            }
    };

    template <typename S>
    struct getOutputImpl<0, S>
    {
        static std::unique_ptr<double> apply(
            PipeOutputClass const* p_Self,
            size_t c_Idx
            )
            {
                std::unique_ptr<double> mydouble(new double(10));
                return mydouble;
            }
    };

    template <typename S>
    struct getOutputImpl<1, S>
    {
        static std::unique_ptr<int> apply(
            PipeOutputClass const* p_Self,
            size_t c_Idx
            )
            {
                std::unique_ptr<int> myint(new int(3));
                return myint;
            }
    };

};

int main()
{

    PipeOutputClass A;
    std::cout << *A.getOutput<0>(0) << std::endl;
    std::cout << *A.getOutput<1>(0) << std::endl;
    return 0;

}

这篇关于使用指向部分专用函数成员的指针自动填充向量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆