Dan*_*rey 11 c++ std enable-if c++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
{};
Run Code Online (Sandbox Code Playgroud)
这适用于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
从未指定的基类继承还是概要绑定并需要直接成员函数?
eca*_*mur 11
关于从基类继承的所有标准都是允许的:
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
{};
Run Code Online (Sandbox Code Playgroud)
这具有平行容器要求(表103 unordered_set
)的优点,这是规范性的,其中概要更倾向于提供信息.