部分函数/方法模板专用化解决方法
Partial function/method template specialization workarounds
我知道函数和类方法不支持部分模板专用化,所以我的问题是:解决此问题的常见解决方案或模式是什么? 下面Derived
派生自Base
,这两个类都有虚方法greet()
和speak()
。 Foo
持有std::array<unique_ptr<T>, N>
,用于do_something()
。 Foo
有两个模板参数:T
(类类型(和N
(std::array
的元素数(如果N
=2,则存在高度优化的do_something()
版本。 现在假设Foo
的T
参数并不总是基类Base
。 理想情况下,我想编写以下代码,但这是非法的:
//ILLEGAL
template<typename T>
void Foo<T,2>::do_something()
{
arr_[0]->greet();
}
下面是完整的代码和我当前的(丑陋的(解决方案。 我必须专攻do_something()
两次,一次用于Base
,一次用于Derived
. 如果存在多个方法(例如 do_something()
(可以在特殊 N
= 2 的情况下进行优化,并且如果存在许多 Base
子类,这会变得丑陋。
#include <iostream>
#include <memory>
class Base
{
public:
virtual void speak()
{
std::cout << "base is speaking" << std::endl;
}
virtual void greet()
{
std::cout << "base is greeting" << std::endl;
}
};
class Derived : public Base
{
public:
void speak()
{
std::cout << "derived is speaking" << std::endl;
}
void greet()
{
std::cout << "derived is greeting" << std::endl;
}
};
template<typename T, int N>
class Foo
{
public:
Foo(std::array<std::unique_ptr<T>, N>&& arr) :
arr_(std::move(arr))
{
}
void do_something();
std::array<std::unique_ptr<T>, N> arr_;
};
template<typename T, int N>
void Foo<T,N>::do_something()
{
arr_[0]->speak();
}
//Want to avoid "copy-and_paste" of do_something() below
template<>
void Foo<Base,2>::do_something()
{
arr_[0]->greet();
}
template<>
void Foo<Derived,2>::do_something()
{
arr_[0]->greet();
}
int main()
{
constexpr int N = 2;
std::array<std::unique_ptr<Derived>, N> arr =
{
std::unique_ptr<Derived>(new Derived),
std::unique_ptr<Derived>(new Derived)
};
Foo<Derived, N> foo(std::move(arr));
foo.do_something();
return 0;
}
诀窍是将实现转发到帮助程序模板类,并部分专用化该类和/或使用标记调度:
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_);
}
有不同的选择,具体取决于问题中的其他约束可能比另一个更合适。
第一个是将请求转发到模板类中的静态函数,这允许部分专用化:
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(基包含差异、派生类型泛型代码并从基中提取特定实现(。
- 检查子类型时的专用方法模板
- 部分方法专用化
- 基于枚举参数调用专用模板方法
- 类中一种方法的部分专用化
- 从非模板类调用专用模板方法
- 使用类指针重载C++命名空间函数模板专用化替代方法?
- 没有针对完全专用模板类的外联虚拟方法定义
- 从部分专用模板方法调用模板非静态方法
- 添加具有模板专用化的方法
- 常量字符*的模板方法专用化
- C++隐式/显式模板方法专用化问题
- enable_if在类声明之外实现的方法专用化
- 类模板:为什么我不能将单一方法专用于空类型?
- 混合显式类专用化和类方法专用化
- 显式模板专用化不能具有存储类 - 成员方法专用化
- 不完整类型(类方法专用化)的使用无效
- 显式模板函数和方法专用化
- *nix 上的模板方法专用化
- "Faking" 具有enable_if的模板类方法专用化
- 用于多种类型的模板方法专用化