在Java中,你可以定义泛型类,它只接受你选择的扩展类的类型,例如:
public class ObservableList<T extends List> {
...
}
这是使用“extends”关键字完成的。
在c++中是否有与此关键字简单等价的东西?
在Java中,你可以定义泛型类,它只接受你选择的扩展类的类型,例如:
public class ObservableList<T extends List> {
...
}
这是使用“extends”关键字完成的。
在c++中是否有与此关键字简单等价的东西?
当前回答
没有用于此类类型检查的关键字,但你可以放入一些至少会以有序方式失败的代码:
(1)如果你想让一个函数模板只接受某个基类X的参数,将它赋给函数中的X引用。 (2)如果你想接受函数但不接受原语,反之亦然,或者你想用其他方式过滤类,在你的函数中调用一个(空的)模板帮助函数,它只为你想接受的类定义。
你也可以在一个类的成员函数中使用(1)和(2)对整个类强制进行这些类型检查。
你可以把它放到一些智能宏来减轻你的痛苦。:)
其他回答
我建议使用Boost的静态断言特性与Boost Type Traits库中的is_base_of一致:
template<typename T>
class ObservableList {
BOOST_STATIC_ASSERT((is_base_of<List, T>::value)); //Yes, the double parentheses are needed, otherwise the comma will be seen as macro argument separator
...
};
在其他一些更简单的情况下,你可以简单地前向声明一个全局模板,但只为有效类型定义(显式或部分专门化):
template<typename T> class my_template; // Declare, but don't define
// int is a valid type
template<> class my_template<int> {
...
};
// All pointer types are valid
template<typename T> class my_template<T*> {
...
};
// All other types are invalid, and will cause linker error messages.
[Minor EDIT 6/12/2013:使用声明但未定义的模板将导致链接器,而不是编译器,错误消息]
好吧,你可以这样创建你的模板:
template<typename T>
class ObservableList {
std::list<T> contained_data;
};
然而,这将使限制成为隐式的,而且您不能只提供任何看起来像列表的东西。还有其他方法来限制所使用的容器类型,例如使用特定的迭代器类型,这些迭代器类型并不存在于所有容器中,但同样,这是一种隐式限制而不是显式限制。
据我所知,目前的标准中不存在完全镜像Java语句的结构。
有一些方法可以通过在模板中使用特定的typedefs来限制在模板中使用的类型。这将确保模板专门化的编译不包括特定的类型定义将失败,所以你可以有选择地支持/不支持某些类型。
在c++ 11中,概念的引入会让这变得更容易,但我不认为它会完全满足你的需求。
没有用于此类类型检查的关键字,但你可以放入一些至少会以有序方式失败的代码:
(1)如果你想让一个函数模板只接受某个基类X的参数,将它赋给函数中的X引用。 (2)如果你想接受函数但不接受原语,反之亦然,或者你想用其他方式过滤类,在你的函数中调用一个(空的)模板帮助函数,它只为你想接受的类定义。
你也可以在一个类的成员函数中使用(1)和(2)对整个类强制进行这些类型检查。
你可以把它放到一些智能宏来减轻你的痛苦。:)
执行摘要:不要那样做。
J_random_hacker的答案告诉您如何做到这一点。然而,我也想指出,你不应该这样做。模板的全部意义在于它们可以接受任何兼容的类型,而Java样式类型约束打破了这一点。
Java的类型约束是一个错误,而不是一个特性。它们存在的原因是Java对泛型进行了类型擦除,因此Java无法弄清楚如何仅根据类型参数的值调用方法。
另一方面,c++没有这样的限制。模板形参类型可以是与使用它们的操作兼容的任何类型。不需要有一个公共基类。这类似于Python的“Duck Typing”,但在编译时完成。
一个简单的例子展示了模板的力量:
// Sum a vector of some type.
// Example:
// int total = sum({1,2,3,4,5});
template <typename T>
T sum(const vector<T>& vec) {
T total = T();
for (const T& x : vec) {
total += x;
}
return total;
}
这个求和函数可以对支持正确运算的任何类型的向量求和。它既适用于int/long/float/double等原语,也适用于重载+=操作符的用户定义数字类型。你甚至可以使用这个函数来连接字符串,因为它们支持+=。
不需要对基本类型进行装箱/解装箱。
注意,它还使用T()构造T的新实例。这在使用隐式接口的c++中是微不足道的,但在使用类型约束的Java中是不可能的。
虽然c++模板没有显式的类型约束,但它们仍然是类型安全的,并且不会使用不支持正确操作的代码进行编译。
只接受类型List派生的类型T的等效函数如下所示
template<typename T,
typename std::enable_if<std::is_base_of<List, T>::value>::type* = nullptr>
class ObservableList
{
// ...
};