Я пытаюсь сделать простой пример для себя, используя новый синтаксис концепции. Я решил проверить, определен ли для типа оператор operator (), и создал структуру для проверки этого с использованием парадигмы SFINAE, но я сталкиваюсь с проблемами типов. Вот мой код:
#include <utility>
#include <functional>
namespace Templates::Concepts {
template<class type__>
struct call_check {
template<class type_ = type__>
static auto check(std::nullptr_t) -> decltype(std::declval<type_>().operator()(), std::false_type(), std::true_type());
template<class type_ = type__>
static auto check(...) -> decltype(std::false_type());
template<class type_ = type__>
using type = decltype(check<type_>(nullptr));
};
template<typename type_>
concept bool Callable = []() -> bool { typename call_check<type_>::type *t; return *t;};
}
Я начал без указателя ‘typename’ и просто
return call_check<type_>::type;
,
но я получил ошибки в зависимости от имени. После добавления typename я теперь получаю
concepts.h:20:78: error: ‘typename Templates::Concepts::call_check<yes>::type’ names ‘template<class type_> using type = decltype (check<type_>(nullptr))’, which is not a type
,
и я застрял Честно говоря, я не совсем уверен, что самый правильный способ — реализовать эту проверку SFINAE, поэтому я не уверен, с чего начать. Любая помощь с парадигмой и / или с концепциями также будет оценена.
Я видел пример с чем-то вроде
std::declval<type_>()(std::declval<other>(), std::declval<op>()), ...
заменив первый элемент в вызове decltype первой проверки (для бинарных операторов), но мне было трудно понять, как это переводится в вызов функции. (Третий ответ сверху, для справки: Как проверить, существует ли оператор ==?).
С концепцией C ++ 20 вы можете избежать «многословного и безобразного» SFINAE парадигма.
Отказ от ответственности: следующий код Совместимость с Gnu Concepts (Концепция C ++ 20 еще не реализована).
Давайте определим следующее концепция который проверяет operator()
существование по типу T
:
template <typename T>
concept bool Callable() {
return requires(T& t) {
{t()}
};
}
Теперь вы можете просто использовать его:
void bar(const Callable& t) {
t();
}
Другое решение может быть получено просто с std::is_invocable
:
Например:
template <typename T>
struct Callable {
static constexpr bool value = std::is_invocable_v<T>;
};
Это C ++ 17 совместимы.
Давайте рассмотрим ваш оригинальный код:
template<class type__>
Двойное подчеркивание в любом месте зарезервировано для реализации.
struct call_check { template<class type_ = type__> static auto check(std::nullptr_t) -> decltype(std::declval<type_>().operator()(), std::false_type(), std::true_type());
Вы обычно не хотите проверять, есть ли что-то operator()
; Вы хотите проверить, может ли он вызываться без аргументов, и нет смысла в , std::false_type()
часть, поэтому конечный тип возврата должен быть
-> decltype(std::declval<type_>()(), std::true_type())
template<class type_ = type__> static auto check(...) -> decltype(std::false_type());
Это излишне многословно. decltype(std::false_type())
просто std::false_type
, Также не требуется аргумент шаблона по умолчанию, так как вы его не используете, поэтому он становится
template<class>
static std::false_type check(...);
template<class type_ = type__> using type = decltype(check<type_>(nullptr));
И здесь нет причин делать этот шаблон псевдонимом. Это должен быть просто псевдоним:
using type = decltype(check<type__>(nullptr)); // modulo reserved identifier.
};
template<typename type_> concept bool Callable = []() -> bool { typename call_check<type_>::type *t; return *t;};
Это неправильно во многих отношениях. Концепция переменных в TS должна быть инициализирована с помощью константного выражения, и лямбда-выражения нельзя использовать в константных выражениях до C ++ 17. Кроме того, вы не сделали вызов лямбда, так что вы неявно преобразуете его в указатель на функцию, а затем bool
, который всегда дает true
, Наконец, на самом деле вызов лямбды будет неопределенным поведением, потому что он разыменовывает неинициализированный указатель.
Самый простой способ записать это
template<typename type_>
concept bool Callable = call_check<type_>::type::value;