Проверка функции-члена: реализовать проверки во время компиляции с помощью функций C ++ 11

Я читал, что C ++ 11 имеет достаточную статическую проверку (время компиляции), чтобы реализовать большую часть того, что должно было быть проверкой концепций C ++ 11 (удалено). (Я читал это в комментариях к недавнему вопросу об удаленных Концепциях … — этот вопрос был быстро закрыт как неконструктивный).

Код C ++ 03 ниже только проверяет наличие функции-члена в классе (над которым хочет работать мой шаблонный класс). Вот 4 функции-члена, которые ищутся, и я всегда использую один и тот же шаблон:

  • определение типа для определения определения типа прототипа функции
  • вызов static_cast, который прерывает компиляцию, если когда-либо имя типа TExtension не определяет такую ​​функцию-член, или если у нее другой прототип

Вот код:

template <typename TExtension>
class
{
...
void checkTemplateConcept()
{
typedef unsigned long (TExtension::*memberfunctionRequestedId)();
static_cast<memberfunctionRequestedId>(&TExtension::getRequestId);

typedef eDirection (TExtension::*memberfunctionDirection)();
static_cast<memberfunctionDirection>(&TExtension::getDirection);

typedef eDriveWay (TExtension::*memberfunctionDriveWay)();
static_cast<memberfunctionDriveWay>(&TExtension::getDriveWay);

typedef unsigned long (TExtension::*memberfunctionCycleId)();
static_cast<memberfunctionCycleId>(&TExtension::getCycleId);
}
}

Это было в какой-то части моего кода, но это было полностью основано на C ++ 03. Я бы с радостью переписал новые возможности C ++ 11… что следует использовать здесь вместо этого?

4

Решение

С C ++ 11 вы могли бы заставить компилятор печатать хорошие сообщения об ошибках с static_assert как:

typedef unsigned long (TExtension::*required_type)();
typedef decltype(&TExtension::getRequestId) actual_type;

static_assert(std::is_same<required_type, actual_type>::value,
"The type of getRequestId must be unsigned long (C::*)()");

Теперь, если тип функции-члена не совпадает, компилятор выведет это полезное сообщение:

"The type of getRequestId must be unsigned long (C::*)()"

Вы можете сделать это более информативным, если хотите. 🙂

6

Другие решения

Да, в C ++ 11 SFINAE был расширен до выражений, поэтому вы можете определить такую ​​черту, как is_t_extension определить наличие функций-членов, например:

template<class... T>
struct holder
{
typedef void type;
};

template<class T, class=void>
struct is_t_extension
: std::false_type
{};

template<class T, class=void>
struct is_t_extension<T, typename holder<
decltype(std::declval<T>().getRequestId),
decltype(std::declval<T>().getDirection),
decltype(std::declval<T>().getDriveWay),
decltype(std::declval<T>().getCycleId)
>::type>
: std::true_type
{};

Теперь это просто проверяет их наличие. С некоторой работой вы могли бы расширить вышеупомянутое, чтобы обнаружить действительные подписи, или вы могли бы использовать Поставить галочку библиотека для записи черты вместо этого, которая выглядит намного чище:

TICK_TRAIT(is_t_extenstion)
{
template<class T>
auto requires_(T&& x) -> TICK_VALID(
returns<unsigned long>(x.getRequestId),
returns<eDirection>(x.getDirection),
returns<eDriveWay>(x.getDriveWay),
returns<unsigned long>(x.getCycleId)
);
};

Тогда в вашем классе вы можете просто использовать static_assert сообщить об ошибке:

template <typename TExtension>
class foo
{
static_assert(is_t_extension<TExtension>(), "Not a TExtension");
};

Или, если вы хотите разрешить специализации, вы можете использовать TICK_CLASS_REQUIRES:

template <typename TExtension, class=void>
class foo;

template <typename TExtension>
class foo<TExtension, TICK_CLASS_REQUIRES(is_t_extension<TExtension>())>
{
...
};
0