Base
,其typename参数为value_type
,DerivedFoo
和DerivedBar
以及DerivedBarCode
和DerivedBarDoge
,源自DerivedBar
,图表:
Base -+---> DerivedFoo <-------+
+-+-> DerivedBar | // Three-way
+---> DerivedBarCode <-+ // conversion
+---> DerivedBarDoge <-+
MatrixBase -+---> DenseMatrix <------------+
+-+-> SparseMatrixBase |
+---> MatrixCSR <------------+ // Multiple-way
+---> MatrixCSC <------------+ // conversion
+---> MatrixModifiedCSR <----+
+---> MatrixModifiedCSC <----+
其中每个类至少有一个公共模板参数typename value_type
。
解释
DerivedBarCode<value_type>
和DerivedBarDoge<value_type>
DerivedFoo<value_type>
。代码:
#include <iostream>
// ----------------------------------------------------------------------------
// Base
// ----------------------------------------------------------------------------
template <typename value_type, typename derived_type>
class Base
{
public:
// Pass along the value type.
typedef value_type value_type;
// Identify myself in the Curiously Recursive Template Pattern hierarchy.
typedef Base object_type;
// Delegate to derived types.
derived_type & asLeaf() { return static_cast<derived_type &>(*this); }
protected:
value_type m_Base;
public:
Base(value_type base = value_type()) : m_Base(base) {}
public:
// A delegated function
void Dump() { asLeaf().Dump(); }
};
// ----------------------------------------------------------------------------
// Base -----> Derived Foo
// ----------------------------------------------------------------------------
template <typename value_type>
class DerivedFoo : public Base < value_type, DerivedFoo<value_type> >
{
public:
// Identify myself in the CRTP hierarchy.
typedef DerivedFoo object_type;
protected:
value_type m_Foo;
public:
DerivedFoo(value_type base = value_type(), value_type foo = value_type()) :
Base < value_type, DerivedFoo<value_type> >(base), m_Foo(foo) {}
template <typename object_type_2>
DerivedFoo(object_type_2 const &other)
{
static_assert(false, "Non-specialized template constructor disabled.");
}
public:
// A possible implementation of the delegated function
void Dump()
{
std::cout << "DerivedFoo = [" << m_Base << ", " << m_Foo << "]\n";
}
};
// ----------------------------------------------------------------------------
// Base -+---> DerivedFoo -+ Two-way
// +---> DerivedBar -+ conversion
// ----------------------------------------------------------------------------
template <typename value_type, typename bar_type>
class DerivedBar : public Base < value_type, DerivedBar<value_type, bar_type> >
{
public:
// Pass along the derived bar type.
typedef bar_type bar_type;
// Identify myself in the CRTP hierarchy.
typedef DerivedBar object_type;
// Delegate to derived types.
bar_type & asLeaf() { return static_cast<bar_type &>(*this); }
protected:
value_type m_Bar;
public:
DerivedBar(value_type base = value_type(), value_type bar = value_type()) :
Base < value_type, DerivedBar<value_type, bar_type> >(base), m_Bar(bar)
{}
public:
void Dump() { asLeaf().Dump(); }
};
// ----------------------------------------------------------------------------
// Base -+---> DerivedFoo <-------+
// +-+-> DerivedBar <-------+ Three-way conversion
// +---> DerivedBarCode <-+
// ----------------------------------------------------------------------------
template <typename value_type>
class DerivedBarCode :
public DerivedBar < value_type, DerivedBarCode<value_type> >
{
public:
typedef DerivedBarCode object_type;
protected:
value_type m_Code = 8;
public:
DerivedBarCode(value_type base = value_type(),
value_type bar = value_type(), value_type code = value_type()) :
DerivedBar < value_type, DerivedBarCode<value_type> >(base, bar),
m_Code(code) {}
public:
void Dump()
{
std::cout << "DerivedBarCode = ["
<< m_Base << ", " << m_Bar << ", " << m_Code << "]\n";
}
};
// DerivedBarCode => DerivedFoo
// Example of what I'm trying to do:
template <typename value_type>
template <>
DerivedFoo<value_type>::DerivedFoo(
typename DerivedBarCode<value_type>::object_type const &other)
{
m_Base = other.m_Base;
m_Foo = other.m_Foo;
// There may be other calculations, e.g. replacing the line above with:
// m_Foo = other.m_Foo + other.m_Code;
std::cout << "m_Code = " << other.m_Code << '\n';
}
// ----------------------------------------------------------------------------
// Base -+---> DerivedFoo <-------+
// +-+-> DerivedBar <-------+ Four-way
// +---> DerivedBarCode <-+ conversion
// +---> DerivedBarDoge <-+
// ----------------------------------------------------------------------------
template <typename value_type>
class DerivedBarDoge :
public DerivedBar < DerivedBarDoge<value_type>, value_type >
{
public:
typedef DerivedBarDoge object_type;
protected:
value_type m_Doge;
public:
DerivedBarDoge(value_type base = value_type(),
value_type bar = value_type(), value_type dance = value_type()) :
DerivedBar < DerivedBarDoge<value_type>, value_type >(base, bar),
m_Code(dance) {}
void Dump()
{
std::cout << "DerivedBarDoge = ["
<< m_Base << ", " << m_Bar << ", " << m_Doge << "]\n";
}
};
// DerivedBarDoge => DerivedFoo
// Another attempt.
template <typename value_type>
template <>
DerivedFoo<value_type>::DerivedFoo(DerivedBarDoge<value_type> const &other)
{
m_Base = other.m_Base;
m_Foo = other.m_Foo;
std::cout << "m_Doge = " << other.m_Doge << '\n';
}
int main()
{
DerivedFoo<double> foo(1.0, 2.0);
foo.Dump();
// Output:
// DerivedFoo = [1, 2];
DerivedBarCode<double> barcode(4.0, 8.0, 16.0);
barcode.Dump();
// Output:
// DerivedBarCode = [4, 8, 16];
DerivedBarDoge<double> bardoge(32.0, 64.0, 128.0);
bardoge.Dump();
// Output:
// DerivedBarDoge = [32, 64, 128];
DerivedFoo<double> converted(barcode);
converted.Dump();
// Expected output:
// DerivedFoo = [4, 8];
converted = bardoge;
converted.Dump();
// Expected output:
// DerivedFoo = [32, 64];
barcode = foo;
barcode.Dump();
// Expected output:
// DerivedFoo = [1, 2, 16];
// system("pause");
return 0;
}
答案 0 :(得分:1)
CRTP基础会将其类名注入派生类。因此,如果每个CRTP基础知道派生类型为derived_type
,那么到达另一个基础other_base< derived_type >
只是一个简单的事情
static_cast< typename derived_type::other_base & >(
static_cast< derived_type & >( * this ) );
如果CRTP base mixin可以通过几个模板中的任何一个实现,那么它应该为自己的类型添加一个typedef,以识别它是哪个mix。然后将其用于::other_base
。
要添加转化,只需将此类广告转换为转化运算符模板即可。在实际尝试之前,请务必使用SFINAE清理转换。
template< typename t,
std::enable_if_t< std::is_base_of_v< t, derived_type > > * = nullptr >
operator t & ()
{ return etc; }
您可以另外/可选地使用成员typedef标记所有合适的mixin,并且SFINAE会检查该标记。要仅选择图表中的过渡,请将标记升级为布尔元函数。
答案 1 :(得分:1)
首先,不要再考虑模板层次结构了。其次,不要再考虑施法了。
这似乎不会留下太多,但它留下足够的。
假设我们有3个不相关的类型:Alice,Bob和Dense。
任何东西都可以轻松转换为密集:
template<typename T>
Dense to_dense( T&& );
现在,有一些自定义代码可让您将Dense转换为Alice或Bob。让我们使用重载,我们传递一个tag参数告诉我们要转换为:
template<class T> struct type_tag {};
Alice from_dense( Dense const&, type_tag<Alice> );
Bob from_dense( Dense const&, type_tag<Bob> );
这些将由Alice
和Bob
尊重地维护。
我们假设Alice
和Bob
属于某种类型 - 称之为ConvertUniverse
:
template<class T>
constexpr bool InConvertUniverse();
我们可以在编译时说InConvertUniverse<Alice>()
并获取true
和InConvertUniverse<int>()
并获取false
。目前,Dense
不在所说的宇宙中。
让我们创建一个可以自动将所述Universe中的任何内容转换为其他内容的函数:
template<class T> using decay_t = typename std::decay<T>::type;
template<class Src, class Dest>
typename std::enable_if<
InConvertUniverse< decay_t<Src> >() && InConvertUniverse< Dest >(),
Dest
>::type
cross_convert( Src&& src, type_tag<Dest> ) {
return from_dense( to_dense(src), type_tag<Dest>{} );
}
现在,cross_convert( alice, type_tag<Bob>{} )
将返回Bob
。
我们可以使用此功能对template
内的任何InConvertUniverse<?>()
实施Alice
强制转换。实际上,我们可以使用它在Alice
的CRTP父级中实现此类强制转换。
对于来自Dense
的投射,你们都很好。
下一步是在特殊情况下允许更快cross_convert
。如果你做到这一点,你将需要使上面的全局cross_convert
具有一些属性,使其不像ADL找到的重载那样优先(例如用...
或{{结束参数列表1}}你从未使用过)。然后我会相信特定的Ts&&...
超载。
现在,令人烦恼的上述错误是ADL不允许我们将cross_convert
粘贴到from_dense
的命名空间中并自动找到它,因为Bob
存在于type_tag<Dest>{}
中不相关的命名空间(理论上)。因此,请将type_tag
替换为:
template<class T> using type_tag = T*;
并且ADL开始启动,我们可以在from_dense
的命名空间中定义Alice
,并通过cross_convert
神奇地找到它。它还会导致协变过载,如果你有Alice
的子类,这很烦人,但这不是问题。