Учитывая тип 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
быть унаследованным от неопределенного базового класса или это синопсис обязательный и требует прямой функции-члена?
Все, что говорит стандарт о наследовании от базовых классов, это то, что оно разрешено:
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
), которые являются нормативными, когда краткие обзоры имеют тенденцию к информативности.
Других решений пока нет …