Проверка существования члена, возможно, в базовом классе, версия C ++ 11

В https://stackoverflow.com/a/1967183/134841 предоставляется решение для статической проверки того, является ли член существует, возможно, в подклассе типа:

template  
class has_resize_method
{ 
   class yes { char m;}; 
   class no { yes m[2];}; 
   struct BaseMixin 
   { 
     void resize(int){} 
   }; 
   struct Base : public Type, public BaseMixin {}; 
   template   class Helper{}; 
   template  
   static no deduce(U*, Helper* = 0); 
   static yes deduce(...); 
public: 
   static const bool result = sizeof(yes) == sizeof(deduce((Base*)(0))); 
};

Однако он не работает с классами C ++ 11 final , поскольку наследуется от тестируемого класса, который final ] предотвращает.

OTOH, этот:

template 
struct has_reserve_method {
private:
    struct No {};
    struct Yes { No no[2]; };
    template  struct sfinae {};
    template  static No  check( ... );
    template  static Yes check( sfinae * );
    template  static Yes check( sfinae * );
public:
    static const bool value = sizeof( check(0) ) == sizeof( Yes ) ;
};

не удается найти метод резерв (int / size_t) в базовых классах.

Существует ли реализация этой метафункции, которая находит reserved () в базовых классах T и по-прежнему работает, если T является final ]?

29
задан Community 23 May 2017 в 12:34
поделиться

1 ответ

На самом деле, все стало намного проще в C ++ 11 благодаря механизму decltype и поздним привязкам.

Теперь для проверки этого проще использовать методы:

// Culled by SFINAE if reserve does not exist or is not accessible
template <typename T>
constexpr auto has_reserve_method(T& t) -> decltype(t.reserve(0), bool()) {
  return true;
}

// Used as fallback when SFINAE culls the template method
constexpr bool has_reserve_method(...) { return false; }

Затем вы можете использовать это в классе, например:

template <typename T, bool b>
struct Reserver {
  static void apply(T& t, size_t n) { t.reserve(n); }
};

template <typename T>
struct Reserver <T, false> {
  static void apply(T& t, size_t n) {}
};

И вы используете его так:

template <typename T>
bool reserve(T& t, size_t n) {
  Reserver<T, has_reserve_method(t)>::apply(t, n);
  return has_reserve_method(t);
}

Или вы можете выбрать метод enable_if:

template <typename T>
auto reserve(T& t, size_t n) -> typename std::enable_if<has_reserve_method(t), bool>::type {
  t.reserve(n);
  return true;
}

template <typename T>
auto reserve(T& t, size_t n) -> typename std::enable_if<not has_reserve_method(t), bool>::type {
  return false;
}

Обратите внимание, что это переключение вещей на самом деле не так просто. В целом, намного проще, когда существует только SFINAE - и вы просто хотите enable_if один метод и не предоставлять какой-либо запасной вариант:

template <typename T>
auto reserve(T& t, size_t n) -> decltype(t.reserve(n), void()) {
  t.reserve(n);
}

Если замена не удалась, этот метод удаляется из списка возможных перегрузок.

Примечание: благодаря семантике , (оператор запятой) вы можете связать несколько выражений в decltype, и только последнее фактически решает тип. Удобно для проверки нескольких операций.

51
ответ дан 28 November 2019 в 01:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: