Concepts/SFINAE typename 错误
Concepts/SFINAE error with typename
我正在尝试使用新概念语法为自己做一个简单的例子。我决定测试一个类型是否定义了 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 检查的最正确方法是什么,因此我不确定从哪里开始。任何对范式 and/or 和概念的帮助也将不胜感激。
我确实看到了一个类似
的例子
std::declval<type_>()(std::declval<other>(), std::declval<op>()), ...
替换第一次检查的 decltype 调用中的第一项(对于二元运算符),但我很难理解它是如何转化为函数调用的。 (倒数第三个答案,供参考:How to check whether operator== exists?)。
使用 C++20 概念,您可以避免 "verbose and ugly" SFINAE 范式。
免责声明:以下代码是Gnu概念兼容(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()
部分没有意义,所以尾随 return 类型应该是
-> 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;
我正在尝试使用新概念语法为自己做一个简单的例子。我决定测试一个类型是否定义了 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 检查的最正确方法是什么,因此我不确定从哪里开始。任何对范式 and/or 和概念的帮助也将不胜感激。
我确实看到了一个类似
的例子std::declval<type_>()(std::declval<other>(), std::declval<op>()), ...
替换第一次检查的 decltype 调用中的第一项(对于二元运算符),但我很难理解它是如何转化为函数调用的。 (倒数第三个答案,供参考:How to check whether operator== exists?)。
使用 C++20 概念,您可以避免 "verbose and ugly" SFINAE 范式。
免责声明:以下代码是Gnu概念兼容(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()
部分没有意义,所以尾随 return 类型应该是
-> 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;