在Java中,你可以定义泛型类,它只接受你选择的扩展类的类型,例如:

public class ObservableList<T extends List> {
  ...
}

这是使用“extends”关键字完成的。

在c++中是否有与此关键字简单等价的东西?


当前回答

只接受类型List派生的类型T的等效函数如下所示

template<typename T, 
         typename std::enable_if<std::is_base_of<List, T>::value>::type* = nullptr>
class ObservableList
{
    // ...
};

其他回答

只接受类型List派生的类型T的等效函数如下所示

template<typename T, 
         typename std::enable_if<std::is_base_of<List, T>::value>::type* = nullptr>
class ObservableList
{
    // ...
};

好吧,你可以这样创建你的模板:

template<typename T>
class ObservableList {
  std::list<T> contained_data;
};

然而,这将使限制成为隐式的,而且您不能只提供任何看起来像列表的东西。还有其他方法来限制所使用的容器类型,例如使用特定的迭代器类型,这些迭代器类型并不存在于所有容器中,但同样,这是一种隐式限制而不是显式限制。

据我所知,目前的标准中不存在完全镜像Java语句的结构。

有一些方法可以通过在模板中使用特定的typedefs来限制在模板中使用的类型。这将确保模板专门化的编译不包括特定的类型定义将失败,所以你可以有选择地支持/不支持某些类型。

在c++ 11中,概念的引入会让这变得更容易,但我不认为它会完全满足你的需求。

在c++中是否有与此关键字简单等价的东西?

No.

根据你想要实现的目标,可能会有足够的(甚至更好的)替代品。

我已经看了一些STL代码(在linux上,我认为它是从SGI的实现派生出来的)。它有“概念断言”;例如,如果您需要一个能够理解*x和++x的类型,则概念断言将在一个什么都不做的函数(或类似的东西)中包含该代码。它确实需要一些开销,所以把它放在一个定义依赖于#ifdef debug的宏中可能是聪明的。

如果子类关系确实是你想知道的,你可以在构造函数中断言T instanceof list(除非它在c++中“拼写”不同)。这样,你就可以通过测试来避免编译器无法为你检查它。

最简单的解决办法是忽略这个问题,虽然还没有人提到过。如果我试图在一个期望容器类(如vector或list)的函数模板中使用int作为模板类型,那么我将得到一个编译错误。粗暴而简单,但它解决了问题。编译器将尝试使用您指定的类型,如果失败,则生成编译错误。

唯一的问题是,您得到的错误消息将很难阅读。然而,这是一种非常常见的方法。标准库中充满了函数或类模板,它们期望从模板类型中获得某些行为,而不做任何检查所使用的类型是否有效的工作。

如果您想要更好的错误消息(或者如果您想要捕捉不会产生编译器错误,但仍然没有意义的情况),您可以根据您想要的复杂程度,使用Boost的静态断言或Boost concept_check库。

使用最新的编译器,可以使用内置的static_assert。

我建议使用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:使用声明但未定义的模板将导致链接器,而不是编译器,错误消息]