使用助手的概念 class
concept using helper class
为了能够为像 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<<
用于 <<','
部分,因此正确地抱怨替换失败。不过我一直以为S代入F失败IsNot An Error,那么为什么 g++ 坚持使用我的自定义 operator<<
作为 <<','
?
这是天赐良机: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 已经附带了完成这项工作所需的工具:Ranges:
template <std::ranges::range R>
std::ostream& operator<<(std::ostream& os, R&& seq);
请注意,由于其他原因,这无论如何都是有问题的,您应该只使用 fmt
,它以正确的方式直接支持 formatting ranges。
为了能够为像 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<<
用于 <<','
部分,因此正确地抱怨替换失败。不过我一直以为S代入F失败IsNot An Error,那么为什么 g++ 坚持使用我的自定义 operator<<
作为 <<','
?
这是天赐良机: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 已经附带了完成这项工作所需的工具:Ranges:
template <std::ranges::range R>
std::ostream& operator<<(std::ostream& os, R&& seq);
请注意,由于其他原因,这无论如何都是有问题的,您应该只使用 fmt
,它以正确的方式直接支持 formatting ranges。