Concepts / SFINAE ошибка с именем типа - PullRequest
0 голосов
/ 23 июня 2018

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

, заменяющим первыйitem в вызове decltype первой проверки (для бинарных операторов), но мне было трудно понять, как это переводится в вызов функции.(Третий ответ сверху, для справки: Как проверить, существует ли оператор ==? ).

Ответы [ 2 ]

0 голосов
/ 23 июня 2018

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

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;
0 голосов
/ 23 июня 2018

С концепцией 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 .

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

...