我知道函数和类方法不支持部分模板特化,所以我的问题是:解决此问题的常见解决方案或模式是什么? Derived
下面的Base
派生自{{ 1}},这两个类都有虚方法greet()
和speak()
。 Foo
包含std::array<unique_ptr<T>, N>
,并在do_something()
中使用。 Foo
有两个模板参数:T
(类类型)和N
(std::array
的元素数量)如果N
= 2,则存在高度优化的do_something()
版本。现在假设Foo
的{{1}}参数并不总是基类T
。理想情况下,我想编写以下代码,但这是非法的:
Base
以下是完整代码和我当前(丑陋)的解决方案。我必须专门//ILLEGAL
template<typename T>
void Foo<T,2>::do_something()
{
arr_[0]->greet();
}
两次,一次为do_something()
,一次为Base
。如果存在多个方法(例如Derived
)可以在特殊do_something()
= 2情况下进行优化,并且存在许多N
的子类,则会变得很难看。
Base
答案 0 :(得分:3)
诀窍是将实现转发给帮助器模板类,并部分专门化该类和/或使用标签分派:
namespace {
template<typename T, int N, bool isBase = std::is_base_of<Base, T>::value>
struct helper {
// general case:
void operator () (std::array<std::unique_ptr<T>, N>& arr_) const
{
arr_[0]->speak();
}
};
template<typename T>
struct helper<T, 2, true>
{
void operator () (std::array<std::unique_ptr<T>, 2>& arr_) const
{
arr_[0]->greet();
}
};
// You may add other specialization if required.
}
template<typename T, int N>
void Foo<T,N>::do_something()
{
helper<T, N>()(arr_);
}
答案 1 :(得分:0)
有不同的选择,取决于问题中的其他约束可能比另一个更合适。
第一个是将请求转发给模板类中的静态函数,该函数允许部分特化:
template <int N>
struct Helper {
template <typename T>
static void talk(T& t) { // Should be T const &, but that requires const members
t.speak();
}
};
template <>
struct Helper<2> {
template <typename T>
static void talk(T& t) {
t.greet();
}
}
然后do_something
的实现将是:
template <typename T, int N>
void Foo<T,N>::do_something() {
Helper<N>::talk(*arr_[0]);
}
或者,您可以使用标记分派来选择多个重载之一:
template <int N> struct tag {};
template <typename T, int N>
template <int M>
void Foo<T,N>::do_something_impl(tag<M>) {
arr_[0]->speak();
}
template <typename T, int N>
void Foo<T,N>::do_something_impl(tag<2>) {
arr_[0]->greet();
}
template <typename T, int N>
void Foo<T,N>::do_something() {
do_something_impl(tag<N>());
}
我创建了一个可以专门用于任何可能N
的标记类型。您还可以使用C ++ 11中的现有工具。
最后,如果你需要为不同的函数做这样的事情,你可以使用继承,并将一些功能推送到解决差异的基础。这可以通过将公共代码推送到基础,差异到中间级别并使用仅从其余部分继承的较低级别前类型来完成(基础包含通用代码,派生类型专门化)。或者使用CRTP(base(s)包含差异,派生类型通用代码并从基础中提取特定实现。