【发布时间】:2014-05-22 09:32:02
【问题描述】:
我写了两个不同的容器类,它们有相同的接口,但是使用不同的成员数据和算法来操作它们的成员。我还有一个模板函数,它接受一个容器并进行一些有用的计算:
class Container1
{
// implementation here
};
class Container2
{
// implementation here
};
template<typename ContainerType>
void my_function(ContainerType const& container, /* other parameters */)
{
// ...
}
困扰我的是'my_function' 应该只接受Container1 或Container2,但这不是由代码表示的,因为ContainerType 可以是任何类型。该函数由容器类型模板化,因为无论容器的内部实现是什么,它都会做同样的事情。
我正在考虑一个变体,其中Container1 和Container2 将是模板类的完全专业化。那我就可以更具体点my_function的论点了:
template<typename T>
class Container;
// Tags to mark different container types
struct ContainerType1 { };
struct ContainerType2 { };
template<>
class Container<ContainerType1>
{
// implementation
};
template<>
class Container<ContainerType2>
{
// implementation
};
template<typename T>
void my_function(Container<T> const& container, /* other parameters */)
{
}
在第一种情况下,如果'ContainerType'没有my_function所需的接口,则模板参数错误的编译将失败,这不是很丰富。在第二种情况下,如果我提供除Container<ContainerType1> 或Container<ContainerType2> 之外的任何其他内容,我也会收到编译器错误(模板参数推导失败),但我更喜欢它,因为它提供了关于预期模板参数类型的提示.
您对此有何看法?这是一个好的设计理念吗?您认为值得更改代码吗?代码中还有很多其他函数,如my_function,有时它们期望什么样的模板参数并不明显。我还有哪些其他选择可以使my_function 更具体?我知道 Boost 概念检查库的存在。
为了论证起见,假设我不想通过使用继承和虚函数来解决问题。
如果与讨论相关,Container1 和Container2 的公共接口是使用 CRTP 强加的。未来可能会有更多的容器类。
【问题讨论】:
-
这是可能的解决方案之一。您也可以使用
std::enable_if或显式模板实例化声明+定义。这两种解决方案都使用 C++11。