如何解决requires子句不兼容
我正在尝试std::iter_value_t使用 C++20 概念实现递归版本,以便可以检索T类似嵌套容器的基本类型std::vector<std::vector<...std::vector<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是它更强大(除了普通别名之外,您还可以拥有别名模板)并且它的语法更加合理(您引入的名称位于=而不是...的左侧)基本上在任何地方)。
第三,正确编写受约束的类模板偏特化的方法是primary是无约束的:
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> {
// ...
};
最后,您的递归步骤是倒退的。如果是范围,则需要先解包,然后递归范围。您目前正在第一次递归 - 但在同一类型上,所以这是无限递归。所以应该是:
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>>
{ };
总而言之[演示]:
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;