指定类模板专业的界面

Specifying an interface common to class template specializations

本文关键字:界面      更新时间:2023-10-16

假设有一些类模板专业知识具有一些常见的公共接口。可以只声明一次吗?

示例:

// Example for a generator
class G
{
public:
    double generate(int channel);
};
template <typename Generator>
class A
{
public:
    double step();
protected:
    Generator g;
};
template <typename Generator, bool fixedMono>
class B;
template <typename Generator>
class B<Generator,true> : public A<Generator>
{
};
template <typename Generator>
class B<Generator,false> : public A<Generator>
{
public:
    void setNumChannels(int numChannels);
private:
    int numChannels;
};
template<typename Generator>
double B<Generator,true>::step() { return A<Generator>::g.generate(0); }
template<typename Generator>
double B<Generator,false>::step()
{
    double sum = 0;
    for (int i = 0; i < numChannels; ++i)
        sum += A<Generator>::g.generate(i);
    return sum;
}

这失败了,因为编译器在B专业化中没有识别step(的确不是)。

在非网络示例中,公共接口可能比单个函数大,并且在所有专业中重复其声明是不可取的。

有没有一个很好的方法来指定一次通用接口?

请注意对上述示例进行重构的建议,因此,除非重构方法是可以始终用于消除此类接口的方法,否则模板专业的具有共同的接口是无关的。问题是,在需要技术上,是否只声明一次这种常见的界面。

一个改进将是使用CRTP。它本身并没有消除每次专业化一次两次声明成员功能的需求,但是至少重复声明是私人实施成员函数,而不是公共接口的函数,仅是一次声明一次。<<<<<<<<<<<<

// Example for a generator
class G
{
public:
    double generate(int channel);
};
template <typename Derived, typename Generator>
class A
{
public:
    double step() { return static_cast<Derived&>(*this)->stepImpl(); };
protected:
    Generator g;
};
template <typename Generator, bool fixedMono>
class B;
template <typename Generator>
class B<Generator,true> : public A<B<Generator,true>, Generator>
{
private:
    double stepImpl();
    using A<B<Generator,true>, Generator>::g;
};
template <typename Generator>
class B<Generator,false> : public A<B<Generator,false>, Generator>
{
public:
    void setNumChannels(int numChannels);
private:
    double stepImpl();
    int numChannels;
    using A<B<Generator,false>, Generator>::g;
};
template<typename Generator>
double B<Generator,true>::stepImpl() { return g.generate(0); }
template<typename Generator>
double B<Generator,false>::stepImpl()
{
    double sum = 0;
    for (int i = 0; i < numChannels; ++i)
        sum += g.generate(i);
    return sum;
}

如果要在类中定义方法,则首先在同一类中声明它。继承允许共享行为,但是在这里,您无论如何都会重新实现整个方法。

主要问题是您无法实现这一目标,因为不允许它。一个很好的解释:https://stackoverflow.com/a/41578586/2504757

下面是另一种方式。使用奇怪的重复模板模式

为默认模板参数定义一个空类

//==================================================================
class NoNumChannels
{};

将步进自己的班级带出来。

//==================================================================
template< typename Generator, typename NumChannels = NoNumChannels >
class Stepper;
template< typename Generator >
class Stepper< Generator, NoNumChannels > // Specialization case when No Numchannels. Just use the generator.
{
public:
    double step()
    {
        return g.generate( 0 );
    }
protected:
    Generator g;
};
template< typename Generator, typename NumChannels > // Otherwise use a class which has NumChannels
class Stepper
{
public:
    double step()
    {
        double sum = 0;
        for (int i = 0; i < (static_cast<NumChannels&>(*this).numChannels_v()); ++i) //Use Curiously recurring template pattern to access num of channels
            sum += g.generate( i );
        return sum;
    }
protected:
    Generator g;
};

B的定义略微修改。对于没有数字的数字仅来自带有发电机的步进的情况。否则,用发电机和自我继承。

//==================================================================
template< typename Generator, bool fixedMono >
class B;
template< typename Generator >
class B< Generator, true > : public Stepper< Generator >
{};
template< typename Generator >
class B< Generator, false > : public Stepper< Generator, B< Generator, false > >
{
public:
    void setNumChannels( int numChannels );
    int numChannels_v();
private:
    int numChannels;
};