如何解决 requires 子句不兼容
How to solve requires clause is incompatible
我正在尝试使用 C++20 概念实现递归版本 std::iter_value_t
,以便可以检索 std::vector<std::vector<...std::vector<T>...>>
等嵌套容器的基本类型 T
。实验实现如下
template<typename T>
concept is_iterable = requires(T x)
{
*std::begin(x);
std::end(x);
};
template<typename T> requires (!is_iterable<T>)
struct recursive_iter_value_t_detail
{
typedef typename T type;
};
template<typename T> requires (is_iterable<T>)
struct recursive_iter_value_t_detail
{
typedef typename std::iter_value_t<typename recursive_iter_value_t_detail<T>::type> type;
};
template<typename T>
using recursive_iter_value_t = typename recursive_iter_value_t_detail<T>::type;
尝试编译此代码后,弹出了唯一的错误消息 'recursive_iter_value_t_detail': requires clause is incompatible with the declaration
,我不确定 requires clause is incompatible with the declaration
是什么意思。问题是template struct不能这样重载吗?请帮我解决这个问题。
recursive_iter_value_t<std::vector<std::vector<int>>>
的预期输出是 int
。
很多东西。
首先,C++20 已经有了可迭代性的概念:它叫做 std::ranges::range
。
其次,自C++11以来,没有理由使用typedef
。总是喜欢using
。使用 typename
也是无效的。所以 using type = T;
而不是 typedef typename T type;
这样做的原因是 using
更强大(除了普通别名之外你还可以有别名模板)并且它是一个更明智的语法(名称您要介绍的是 =
的左侧,而不是...基本上任何地方)。
第三,正确编写约束class模板偏特化的方法是主是无约束的:
template <typename T>
struct recursive_iter_value_t_detail {
using type = T;
};
和其他 (a) 比 主要限制更多,并且 (b) 实际上必须是专业化的(请参阅语法中的额外 <T>
):
template <typename T> requires std::ranges::range<T>
struct recursive_iter_value_t_detail<T> {
// ...
};
也可以这样拼写:
template <std::ranges::range T>
struct recursive_iter_value_t_detail<T> {
// ...
};
最后,你的递归步骤是倒退的。如果它是一个范围,则需要 first 解包并且范围 then 递归。您目前首先递归——但在同一类型上,所以这是无限递归。所以应该是:
using type = recursive_iter_value_t_detail<std::iter_value_t<T>>::type;
你可以把它写得更短:
template <std::ranges::range T>
struct recursive_iter_value_t_detail<T>
: recursive_iter_value_t_detail<std::iter_value_t<T>>
{ };
总而言之[demo]:
template<typename T>
struct recursive_iter_value_t_detail
{
using type = T;
};
template <std::ranges::range T>
struct recursive_iter_value_t_detail<T>
: recursive_iter_value_t_detail<std::iter_value_t<T>>
{ };
template<typename T>
using recursive_iter_value_t = typename recursive_iter_value_t_detail<T>::type;
我正在尝试使用 C++20 概念实现递归版本 std::iter_value_t
,以便可以检索 std::vector<std::vector<...std::vector<T>...>>
等嵌套容器的基本类型 T
。实验实现如下
template<typename T>
concept is_iterable = requires(T x)
{
*std::begin(x);
std::end(x);
};
template<typename T> requires (!is_iterable<T>)
struct recursive_iter_value_t_detail
{
typedef typename T type;
};
template<typename T> requires (is_iterable<T>)
struct recursive_iter_value_t_detail
{
typedef typename std::iter_value_t<typename recursive_iter_value_t_detail<T>::type> type;
};
template<typename T>
using recursive_iter_value_t = typename recursive_iter_value_t_detail<T>::type;
尝试编译此代码后,弹出了唯一的错误消息 'recursive_iter_value_t_detail': requires clause is incompatible with the declaration
,我不确定 requires clause is incompatible with the declaration
是什么意思。问题是template struct不能这样重载吗?请帮我解决这个问题。
recursive_iter_value_t<std::vector<std::vector<int>>>
的预期输出是 int
。
很多东西。
首先,C++20 已经有了可迭代性的概念:它叫做 std::ranges::range
。
其次,自C++11以来,没有理由使用typedef
。总是喜欢using
。使用 typename
也是无效的。所以 using type = T;
而不是 typedef typename T type;
这样做的原因是 using
更强大(除了普通别名之外你还可以有别名模板)并且它是一个更明智的语法(名称您要介绍的是 =
的左侧,而不是...基本上任何地方)。
第三,正确编写约束class模板偏特化的方法是主是无约束的:
template <typename T>
struct recursive_iter_value_t_detail {
using type = T;
};
和其他 (a) 比 主要限制更多,并且 (b) 实际上必须是专业化的(请参阅语法中的额外 <T>
):
template <typename T> requires std::ranges::range<T>
struct recursive_iter_value_t_detail<T> {
// ...
};
也可以这样拼写:
template <std::ranges::range T>
struct recursive_iter_value_t_detail<T> {
// ...
};
最后,你的递归步骤是倒退的。如果它是一个范围,则需要 first 解包并且范围 then 递归。您目前首先递归——但在同一类型上,所以这是无限递归。所以应该是:
using type = recursive_iter_value_t_detail<std::iter_value_t<T>>::type;
你可以把它写得更短:
template <std::ranges::range T>
struct recursive_iter_value_t_detail<T>
: recursive_iter_value_t_detail<std::iter_value_t<T>>
{ };
总而言之[demo]:
template<typename T>
struct recursive_iter_value_t_detail
{
using type = T;
};
template <std::ranges::range T>
struct recursive_iter_value_t_detail<T>
: recursive_iter_value_t_detail<std::iter_value_t<T>>
{ };
template<typename T>
using recursive_iter_value_t = typename recursive_iter_value_t_detail<T>::type;