c++ - 类型名称的概念/SFINAE 错误

标签 c++ templates sfinae c++-concepts declval

我正在尝试使用新概念语法为自己做一个简单的例子。我决定测试一个类型是否定义了 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; ,

但我收到了与名称相关的类型错误。添加我现在收到的类型名后

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 调用中的第一项(对于二元运算符),但我很难理解它是如何转换为函数调用的。 (倒数第三个答案,供引用:How to check whether operator== exists?)。

最佳答案

让我们来处理您的原始代码:

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 之前的常量表达式中不能使用 lambda。此外,您没有调用 lambda,因此您将其隐式转换为函数指针,然后转换为 bool,这始终会产生 true .最后,实际调用 lambda 将是未定义的行为,因为它解引用了一个未初始化的指针。

最简单的拼写方式是

 template<typename type_>
 concept bool Callable = call_check<type_>::type::value;

关于c++ - 类型名称的概念/SFINAE 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51003709/

相关文章:

c++ - 在纯 native 代码中使用托管对象

c++ - 使用可变参数模板创建模板类元组

c++ - 控制更复杂的tuple_for_each的多个可变参数包的拆包

c# - 如何获取 Windows 服务自定义状态? [C++/C#]

c++ - 不使用字符串也不除以 10 的数字到数字

c++ - 用值替换表达式?

c++ - 数据不匹配和编译器无法推断模板参数

angular - <ng-template></ng-template> 正在加载多次

c++ - 用函数模板和SFINAE按参数区分

c++ - Boost.花 : How to check if function has specialisation for a certain type?