11

给定一个C符合 STL 的容器类型,我如何正确检测是否C包含成员函数reserve?我尝试了以下方法(使用 GCC 4.6.3):

template< typename C, typename = void >
struct has_reserve
  : std::false_type
{};

template< typename C >
struct has_reserve< C, typename std::enable_if<
                         std::is_same<
                           decltype( &C::reserve ),
                           void (C::*)( typename C::size_type )
                         >::value
                       >::type >
  : std::true_type
{};

这适用于Cbeing std::vector,但不适用于无序容器,例如std::unordered_set。原因是,那reserve是 的(直接)成员函数std::vector,但对于无序容器,它是从基类继承的,即它的签名不是void (C::*)( typename C::size_type ),而是void (B::*)( typename C::size_type )针对 的某些未指定的基BC

我知道如何解决它并检测reserve即使是继承的,但它看起来很笨拙,我想知道标准允许什么。所以...

我的问题是:标准是否允许reserve从未指定的基类继承,还是概要绑定并需要直接成员函数?

4

1 回答 1

12

所有关于从基类继承的标准都是允许的:

17.6.5.11 派生类[派生]

1 - 实现可以从具有为实现保留名称的类派生 C++ 标准库中的任何类。

它并没有说明是否允许从基类继承方法(实际上还有其他成员,例如 typedefs)。显然,由于实现是这样做的,标准应该描述这种行为。

在任何情况下,reserve即使是最派生类型的成员,也不能保证通过强制转换为成员函数类型进行检测,因为:

17.6.5.5 成员函数[member.functions]

2 - 一个实现可以在一个类中声明额外的非虚拟成员函数签名:

  • 通过将具有默认值的参数添加到成员函数签名186;[...]

186) 因此,C++ 标准库中类的成员函数的地址具有未指定的类型。

检查是否reserve存在的正确方法是尝试调用它:

template< typename C, typename = void >
struct has_reserve
  : std::false_type
{};

template< typename C >
struct has_reserve< C, typename std::enable_if<
                         std::is_same<
                           decltype( std::declval<C>().reserve( std::declval<typename C::size_type>() ) ),
                           void
                         >::value
                       >::type >
  : std::true_type
{};

这具有并行容器要求(表 103 的unordered_set)的优点,这是规范的,其中提要更倾向于提供信息。

于 2013-02-14T21:11:33.533 回答