问题描述
我在考虑模板专业化,想知道是否存在一种使用部分专业化的方法来生成两个不同的代码路径,这些路径会自动合并。
在这种情况下,我有一个计算引擎,希望在枚举时在编译时选择不同的函数。在这种情况下,取决于policy
或scheme
,我希望在编译时使用不同的函数。
我当时认为我可以避免显式地部分化所有变体。这可能吗?
#include <iostream>
enum class scheme { linear,polynomial };
enum class policy { no_checking,raise_exception };
struct computational_base
{
void left();
void middle();
void do_stuff()
{
left();
middle();
}
};
template <scheme scheme,policy left>
struct computational_backend : public computational_base
{
};
template <policy left>
struct computational_backend<scheme::linear,left> : public computational_base
{
void middle()
{
std::cout << "scheme::linear" << std::endl;
}
};
template <scheme scheme>
struct computational_backend<scheme,policy::no_checking> : public computational_base
{
void left()
{
std::cout << "policy::no_checking" << std::endl;
}
};
int main()
{
//Ideally would select middle() from first template,and left() from second template
// more than one partial specialization matches the template argument list
computational_backend<scheme::linear,policy::no_checking> what;
what.do_stuff();
return 0;
}
解决方法
CRTP和多重继承可以成为您的朋友。在核心,您可以使用多重继承从两个类中引入功能
template <scheme s,policy p>
struct computational_backend
: scheme_backend<s>,policy_backend<p>
{ };
只要计算过程的不同部分不需要相互调用,这种事情就可以工作。换句话说,它在Middle()永远不需要调用left()时有效,反之亦然。
如果您需要他们彼此调用,那么好奇递归模板模式(CRTP)是您的朋友。这是一个奇怪的问题,基本上可以让您从基类转换为派生最多的类型,因为您将派生最多的类型作为模板参数传入。看起来像这样:
template <typename DerivedT,scheme s>
struct scheme_backend;
template <typename DerivedT,policy p>
struct policy_backend;
template <typename DerivedT>
struct scheme_backend<DerivedT,scheme::linear>
{
DerivedT& derived()
{
return *static_cast<DerivedT*>(this);
}
void left()
{
...
derived().middle();
...
}
};
template <scheme s,policy p>
struct computational_backend
: scheme_backend<computational_backend<s,p>,s>,policy_backend<computational_backend<s,p>
{ };
我只画了其中一个专业,但是您明白了。事实证明,奇怪的静态类型转换不仅在C ++中合法,而且实际上非常快。在许多情况下,编译器可以完全对其进行优化。