C++ 部分模板专业化 - 设计简化

C++ Partial template specialization - design simplification

我正在研究 pipeline/dataflow 设计模式。我有一个 class 'algorithm data output' (AlgorithmOutput) 作为两个相连网段之间的接口。特别是,它提供了方法模板 getOutput<size_t N>,用于从 'data transmitter' 类型的对象输出数据。

当前的设计基于用户从class AlgorithmOutput 派生并提供有限数量的方法模板实现的想法getOutput<size_t N>。我还需要能够允许用户从方法 getOutput 中提供他们自己的自定义 return 类型(即 return 类型不能是多态的)。此外,有必要让 getOutput 的所有实现都能够访问定义为方法所属的 class 成员的同一数据集。

当前解决方案在用户派生的 classes 中使用部分显式特化来定义方法 getOutput 的不同实现。我想简化解决方案,如果有任何关于如何在不丢失当前设计功能的情况下完成此操作的想法,我将不胜感激。

编辑:从用户的角度来看,我只关心方法 getOutput 的易用性。我不关心基础 classes.

的实现有多复杂

实例派生的实现class:

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;
            }
    };

};

您可以使用标签分派来避免部分特化的需要。简化版:

//we'll use this to overload functions based on a size_t template param
template <size_t N>
struct Size2Type{};

class PipeOutputClass
{
public:
    template <size_t N>
    auto getOutput(size_t c_Idx) const
    {
        //use Size2Type to tag dispatch
        return getOutputImpl(Size2Type<N>{}, c_Idx);
    }

    //default version for when we don't explicitly provide an overload
    template <size_t N>
    auto getOutputImpl(Size2Type<N>, size_t c_Idx) const
    {
         throw std::runtime_error("Wrong template argument.");
    }

    //overload for when N = 0
    std::unique_ptr<double> getOutputImpl (Size2Type<0>, size_t c_Idx) const
    {
        std::unique_ptr<double> mydouble(new double(10));
        return mydouble;
    }

    //overload for when N = 1
    std::unique_ptr<int> getOutputImpl (Size2Type<1>, size_t c_Idx) const
    {
        std::unique_ptr<int> myint(new int(3));
        return myint;
    }
};