假设一些类模板特化有一些共同的公共接口。是否可以只声明一次?
示例:
// 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;
}
这会失败,因为编译器无法识别step
特化中声明的B
(实际上,它不是)。
在非玩具示例中,公共接口可能比单个函数大,并且在所有特化中重复其声明是不可取的。
有没有很好的方法只指定一次公共接口?
请注意重构上述示例的建议,因此除非重构方法总是用于消除此类接口,否则模板专业化不需要具有公共接口无关紧要。问题是,在需要的情况下,是否只需要声明一次这样的通用接口在技术上是可行的。
答案 0 :(得分:0)
一个改进是使用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;
}
答案 1 :(得分:0)
如果要在类中定义方法,首先要在同一个类中声明它。继承允许共享行为,但在这里,你重新实现了整个方法。
答案 2 :(得分:0)
主要问题是你无法实现这一点,因为它是不允许的。 一个很好的探索:https://stackoverflow.com/a/41578586/2504757
以下是另一种方式。使用Curiously recurring template pattern
为默认模板参数
定义一个空类//==================================================================
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的定义略有修改。对于没有NumChannels的情况,只需继承Stepper with Generator。否则继承自Stepper with Generator和self。
//==================================================================
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;
};