Я читал, что C ++ 11 имеет достаточную статическую проверку (время компиляции), чтобы реализовать большую часть того, что должно было быть проверкой концепций C ++ 11 (удалено). (Я читал это в комментариях к недавнему вопросу об удаленных Концепциях … — этот вопрос был быстро закрыт как неконструктивный).
Код C ++ 03 ниже только проверяет наличие функции-члена в классе (над которым хочет работать мой шаблонный класс). Вот 4 функции-члена, которые ищутся, и я всегда использую один и тот же шаблон:
Вот код:
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… что следует использовать здесь вместо этого?
С 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::*)()"
Вы можете сделать это более информативным, если хотите. 🙂
Да, в 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>())>
{
...
};