Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
159 views
in Technique[技术] by (71.8m points)

c++ - Correct signature of / detect presence of Container::reserve()

Given a type C which is an STL-conforming container, how do I correctly detect if C contains a member function reserve? I tried the following approach (with 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
{};

This works for C being std::vector, but not for the unordered containers, e.g. std::unordered_set. The reason is, that reserve is a (direct) member function of std::vector, but for the unordered containers it is inherited from a base class, i.e., its signature is not void (C::*)( typename C::size_type ) but void (B::*)( typename C::size_type ) for some unspecified base class B of C.

I know how to work around it and detect reserve even if inherited, but it looks clumsy and I wonder what is allowed by the standard. So...

My question is: Does the standard allow reserve to be inherited from an unspecified base class or is the synopsis binding and requires a direct member function?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

All the standard says about inheritance from base classes is that it is allowed:

17.6.5.11 Derived classes [derivation]

1 - An implementation may derive any class in the C++ standard library from a class with a name reserved to the implementation.

It doesn't say either way whether methods (and, indeed, other members such as typedefs) are allowed to be inherited from a base class; obviously, since implementations do so, the standard should describe this behaviour.

In any case, detecting e.g. reserve by cast to a member function type is not guaranteed to work even if a member of the most derived type, since:

17.6.5.5 Member functions [member.functions]

2 - An implementation may declare additional non-virtual member function signatures within a class:

  • by adding arguments with default values to a member function signature186; [...]

186) Hence, the address of a member function of a class in the C++ standard library has an unspecified type.

The correct way to check whether reserve exists is to attempt to call it:

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
{};

This has the advantage of paralleling the container requirements (table 103 for unordered_set), which are normative where the synopses tend more to the informative.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...