概念使用helper类



为了能够为像vector<int> vec;这样的可迭代类型编写像cout << vec这样的东西,我想只为可迭代的T定义operator<<(osteam&, const T&)。我的第一个镜头是

template<class T> using extract_iterator_t = typename T::iterator;
template<class T> concept iterable = requires { typename extract_iterator_t<T>; };
template<iterable T>
ostream& operator<<(ostream& os, const T& seq) {
for(const auto& i: seq) os << i << ',';
return os;
}

,但这遗漏了可迭代的内容,比如int*,所以我用

代替了第一行
template<class T> struct extract_iterator { using type = T::iterator; };
template<class T> struct extract_iterator<T*> { using type = T*; };
template<class T> struct extract_iterator<T[]> { using type = T*; };
template<class T> using extract_iterator_t = typename extract_iterator<T>::type;

但是,现在g++-11.1拒绝编译它,说

error: 'char' is not a class, struct, or union type

,因为它试图使用我的自定义operator<<<<','部分,正确地抱怨替换失败。然而,我一直认为SF 我ailureN sotE n错误,那么为什么g++坚持使用我的自定义operator<<来代替<<','呢?这是godbolt: https://godbolt.org/z/jejexE18h

编辑:每个人都指出范围是正确的,它们是正确的工具,但这个例子只是为了说明一个问题,我有一个类似的结构,但不等于范围-我想我应该提出一个最小的突破性的例子,而不是告诉一个很长的介绍性的故事,归结为同样的问题。

问题是,在您的主要定义中:

template <class T> struct extract_iterator { using type = T::iterator; };

当我们尝试执行T::iterator时发生的失败不在替换的直接上下文中,因此它不是sfinae友好的。

您可以通过添加正确的约束来解决这个问题:

template<class T> struct extract_iterator;
template<class T> requires requires { typename T::iterator; }
struct extract_iterator<T> { using type = T::iterator; };

但这整个方法无论如何都是错误的。T*不是可迭代的,它是一个迭代器。而且c++ 20已经提供了完成这项工作所需的工具:范围:

template <std::ranges::range R>
std::ostream& operator<<(std::ostream& os, R&& seq);

请注意,由于其他原因,这无论如何都是有问题的,您应该使用fmt,它以适当的方式直接支持格式化范围。

相关内容

  • 没有找到相关文章

最新更新