Concepts / SFINAE ошибка с именем типа

Я пытаюсь сделать простой пример для себя, используя новый синтаксис концепции. Я решил проверить, определен ли для типа оператор 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 первой проверки (для бинарных операторов), но мне было трудно понять, как это переводится в вызов функции. (Третий ответ сверху, для справки: Как проверить, существует ли оператор ==?).

1

Решение

С концепцией 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();
}

GodBolt Полный Пример.


Другое решение может быть получено просто с std::is_invocable:

Например:

template <typename T>
struct Callable {
static constexpr bool value = std::is_invocable_v<T>;
};

Это C ++ 17 совместимы.

Пример здесь.

1

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

Давайте рассмотрим ваш оригинальный код:

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;
3

По вопросам рекламы [email protected]