问题 正确签名/检测Container :: reserve()的存在


给定一种类型 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
{};

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

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

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


12024
2018-02-14 19:31


起源



答案:


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

17.6.5.11派生类[派生]

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

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

在任何情况下,检测例如 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),这是规范性的,其中概要更倾向于提供信息。


11
2018-02-14 21:11



+1但你应该打电话 reserve(1) 或类似的。 - Olaf Dietsche
不在VS2012下编译。会有替代方案吗? - Alex O


答案:


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

17.6.5.11派生类[派生]

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

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

在任何情况下,检测例如 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),这是规范性的,其中概要更倾向于提供信息。


11
2018-02-14 21:11



+1但你应该打电话 reserve(1) 或类似的。 - Olaf Dietsche
不在VS2012下编译。会有替代方案吗? - Alex O