假设我有一个派生类Derived
。除了获取模板参数外,Derived
还是Base
的派生类,而Derived
依次模仿template <int i, typename T>
class Derived : public Base<Derived<i,T>>
{
};
template <typename DerivedType>
class Base
{
};
。
以下说明了一个工作解决方案的示例:
Derived
然而,当this
的模板参数列表变大时,这变得很麻烦,因为想要将派生类添加到库的编码器必须两次编写模板参数。反正是以某种方式自动化这个吗?
以下是我所追求的内容(以下内容未编译,因为template <int i, typename T>
class Derived : public Base<decltype(*this)>
{
};
template <typename DerivedType>
class Base
{
};
尚不存在,但它说明了我正在寻找的内容):
{{1}}
如果没有办法通过模板实现这一点,我会接受一个优雅的宏观解决方案(也许是矛盾的吗?)。
答案 0 :(得分:1)
使用traits类来包含元数据,而不是传递参数列表中的每个项目。
这就是我在图书馆里做的事情,我很快就会开源。
首先,有一个默认的traits类来覆盖常见的情况。我想处理一系列常见案例,因此它也是一个模板,但除此之外它可能是一个普通的类。参数化只是对用户来说很方便,而不是最终的详细实现参数化,而是包含其内容。
template< typename rep_type, unsigned mantissa_values, rep_type fractional_cycles >
struct positive_logarithm_default_traits {
typedef double conv_basis;
static constexpr bool range_check = true;
typedef rep_type rep;
protected:
static constexpr rep max_rep = std::numeric_limits< rep >::max();
static constexpr rep unity_rep = mantissa_values * fractional_cycles;
// Another specialization could overflow to INFINITY and underflow to 0.
[[noreturn]] static rep underflow() { throw range_error( false ); }
[[noreturn]] static rep overflow() { throw range_error( true ); }
};
然后我定义一个元函数来将类的一个实例转换为另一个实例。它在traits类空间内工作,如果将多个元处理转换串在一起,可以通过消除中间结果的实例化来帮助编译时间。
// The traits of a logarithm which represents the inverse of another logarithm.
template< typename traits >
struct inverse_traits : traits {
static constexpr decltype( traits::unity_rep ) unity_rep
= traits::max_rep - traits::unity_rep;
};
虽然traits类通常只包含编译时数据,但我通过继承它来允许运行时变化。在这种情况下,traits类也可能希望访问派生类的状态。这基本上是CRTP。但是,给定的traits类可能希望使用非traits参数化为几个最终派生类提供服务。所以我创建了一个额外的类,其中运行状态可以通过static_cast< logarithm_state_base< traits > >( * this )
访问traits类 - 这在功能上等同于CRTP,但避免了很多元编程的复杂性。
template< typename traits >
class logarithm_state_base : public traits {
protected:
typename traits::rep log_value;
};
最后,派生类为用户提供与默认traits类解释相同的便捷界面。但是,在内部,它通过从traits类继承的成员引用所有元数据。
如果用户定义了自己的traits类,则typename traits_type
之前的模板参数(mantissa_values除外)是残留的和未使用的。别名模板可以将它们全部设置为void
,以提供基于特征的用户界面。或者,如果我预计特征使用会更受欢迎,我可以用另一种方式做,让特质成为&#34;本地&#34;接口和逐项参数是方便别名。
template<
typename rep, // Underlying representation type
unsigned mantissa_values, // # distinct values per power of 2
rep fractional_cycles = std::numeric_limits< rep >::max() / ( mantissa_values * 2 ) + 1,
typename traits_type = positive_logarithm_default_traits< rep, mantissa_values, fractional_cycles >
>
class static_positive_logarithm
: public logarithm_state_base< traits_type > {
static_assert ( std::is_unsigned< typename traits_type::rep >::value,
"Representation type must be unsigned." );
…
答案 1 :(得分:0)
template <int i, typename X>
struct Derived
{
class T : public Base<T> { ... };
};
Derived<2, char>::T x;