作为模板函数参数的完全特化类
Fully specialized class as template function parameter
我编写了两个不同的容器类,它们具有相同的接口,但使用不同的成员数据和算法来操作其成员。我也有一个模板函数,它接受一个容器并做一些有用的计算:
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强加的。将来可能会有更多的容器类
对于这类问题有几种解决方法。
你的解决方案(实现你的类型作为template
专门化)是一个,但我不是特别喜欢。
template<typename T>
struct Container {
// optional, but I find it helpeful
T* self() { return static_cast<T*>(this); }
T const* self() const { return static_cast<T const*>(this); }
// common code between every implementation goes here. It accesses itself through self(), never this
};
class ContainerType1: public Container<ContainerType1> {
// more details
};
class ContainerType2: public Container<ContainerType2> {
// more details
};
这是CRTP的核心。
:
template<typename T>
void my_function(Container<T> const& container_, /* other parameters */)
{
T const& container = *(container.self());
}
Bob是你的叔叔。作为奖励,这提供了放置公共代码的地方。
另一个选项是标记特征类,标记你想要支持的类型,如iterator_traits
。
template<typename T>
struct is_container : std::false_type {};
template<>
struct is_container<ContainerType1> : std::true_type {};
template<>
struct is_container<ContainerType2> : std::true_type {};
你甚至可以做SFINAE风格的模式匹配来检测基类型(就像迭代器的工作方式一样)。
现在你的方法可以在is_container<T>::value
上测试,或者在is_container<T>{}
上做标签调度。
我认为你的第一个版本是可行的。
在一天结束的时候,你总是要选择最优的方法。第二个可能看起来有点矫枉过正,尽管它表达了重点。如果您的容器类都有一个共同的函数(假设是Container1::hasPackage() or Container2::hasPackage()
),并且您选择在my_function
中调用它,那么它会直接表明您的观点,即调用它的资格是该函数本身。在经历了许多这样的项目之后,您将开始以相反的方式阅读模板——从模板定义开始——以查看限定一个特定类所需的最少属性。
说了这么多,也许你的问题更适合Code Review
我在ideone上创建的一个例子是使用您的类,但将name
成员变量添加到它们中,这是my_function
所期望的。当然,可能会有支持name
的类,但开发人员也可能会花几次时间来实现函数背后的思想。
- 将可变参数函数的参数封装在类实例中
- QML 使用带有参数C++函数
- 使用可变参数函数作为模板参数
- 如何在C++中伪造虚拟可变参数函数模板?
- 为什么可变参数函数不适用于模板
- C++ std::functional 中的可变参数函数模板
- 可变参数函数指针的定义对于VxWorks spyLib来说不清楚
- 使用可变参数函数覆盖具有不同函数签名的虚函数
- 考虑引用和常量的可变参数函数包装器
- 使用可变参数函数将整数和/或整数数组放入单个 int 数组中
- 在可变参数函数中转发特定范围的参数
- 通过引用传递参数;函数返回类型是否必须为 VOID?
- 使用带有一个参数函数的递归找到数字的平方
- 可变参数函数模板不能很好地使用 std::function 作为参数
- 多个可变参数函数的单个模板参数包?
- 参数数据类型未知的可变参数函数
- 可变参数函数参数包扩展
- 使用模板可变参数函数将多个参数传递给另一个函数
- 对可变参数函数的递归调用的链接器错误
- 通过像printf这样的可变参数函数传递一个带有常量字符*转换函数的类