如何解决模板类型上std :: is_invocable的意外结果
我有一个if constexpr
检查类型是否与其自身相等。我使用std::is_invocable_v<std::equal_to<>,T,T>
。
但是,当T
是无与伦比的结构的向量时,该代码段错误地返回True。有深层原因吗?还是编译器错误?
下面是最小的示例。
#include <type_traits>
#include <iostream>
#include <vector>
class TNonComparable{};
int main()
{
std::cout << std::is_invocable_v<std::equal_to<>,TNonComparable,TNonComparable> << "\n";
// 0
std::cout << std::is_invocable_v<
std::equal_to<>,std::vector<TNonComparable>,std::vector<TNonComparable>
> << "\n";
// 1
std::vector<TNonComparable> vec;
// vec == vec;
// (expected) compilation error
}
我检查了Godbolt的输出,所有最新版本的g ++和clang都一样。
解决方法
我认为look at std::is_invocable
的作用非常重要:
确定是否可以使用参数
Fn
调用ArgTypes...
。 正式确定INVOKE(declval<Fn>(),declval<ArgTypes>()...)
在被视为未评估值时是否格式正确 操作数,其中INVOKE
是Callable
中定义的操作。
强调地雷。
这里要注意的重要部分是,std::equal_to<>
中使用的std::is_invocable
永远不会被求值,因为它是未求值的操作数。这意味着它仅检查operator==
是否存在,而对std::vector<>
这样做,而不检查它是否可以在评估的上下文中进行编译。
我认为这是正确的行为。
在第一个std::is_invokable_v
中检查operator==
类型的TNonComparable
的存在。它不存在-结果为0。
在第二种情况下,std::is_invokable_v
检查std::vector
的相等运算符,该运算符存在并且可以被调用。但是,如果要尝试调用它,它将无法编译,因为TNonComparable
类型没有operator==
。但是在您不尝试使用它之前,它不会产生错误。
也许,在第二种情况下,您应该检查std :: vector的value_type:
std::cout << std::is_invocable_v<
std::equal_to<>,std::vector<TNonComparable>::value_type,std::vector<TNonComparable>::value_type
> << "\n";
// 0
,
花了一些时间,我已经写了解决方法工具
namespace detail
{
template<typename T,typename=void>
struct has_value_type : std::false_type {};
template<typename T>
struct has_value_type<T,std::void_t<typename T::value_type>> : std::true_type {};
template<typename T,typename=void>
struct is_pair : std::false_type {};
template<typename T,typename U>
struct is_pair<std::pair<T,U>,void> : std::true_type {};
template<typename T,typename=void>
struct is_tuple : std::false_type {};
template<typename ...Args>
struct is_tuple<std::tuple<Args...>,void> : std::true_type {};
}
template<typename T,typename=void>
struct has_euqual_operator : std::false_type {};
template<typename T>
struct has_euqual_operator<
T,std::void_t<
std::enable_if_t<
!detail::is_pair<T>::value
&& !detail::has_value_type<T>::value
&& !detail::is_tuple<T>::value>,decltype(std::declval<T>() == std::declval<T>())
>
> : std::true_type
{};
template<typename T>
struct has_euqual_operator<
T,std::enable_if_t<has_euqual_operator<typename T::value_type>::value>
> : std::true_type
{};
template<typename T>
struct has_euqual_operator<
T,std::enable_if_t<has_euqual_operator<typename T::first_type>::value
&& has_euqual_operator<typename T::second_type>::value
>
> : std::true_type
{};
template<typename ...Args>
struct has_euqual_operator<
std::tuple<Args...>,std::enable_if_t<(... && has_euqual_operator<Args>::value)>
> : std::true_type
{};
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。