I am learning fold expressions in C++17. I have the following code
#include <iostream>
#include <vector>
namespace io {
template<typename T>
std::istream &operator>>(std::istream &in, std::vector<T> &vec) {
for (auto &x : vec)
in >> x;
return in;
}
template<class... Args> void scan(Args &... args) {
(std::cin >> ... >> args);
}
}// namespace io
int main() {
std::vector<int> s(1), t(1);
io::scan(s, t);
std::cout << s[0] << ' ' << t[0] << '\n';
}
Using GCC 9.3.0, the code compiles and runs correctly, but using Clang 10.0.0, the same code does not compile:
<source>:13:16: error: call to function 'operator>>' that is neither visible in the template definition nor found by argument-dependent lookup
(std::cin >> ... >> args);
^
<source>:19:9: note: in instantiation of function template specialization 'io::scan<std::vector<int, std::allocator<int> >, std::vector<int, std::allocator<int> > >' requested here
io::scan(s, t);
^
<source>:6:15: note: 'operator>>' should be declared prior to the call site
std::istream &operator>>(std::istream &in, std::vector<T> &vec) {
^
1 error generated.
Why clang rejets the code but gcc accepts it?
This was a Clang bug. Clang versions 11 and earlier did not properly implement two-phase name lookup for the operator in a fold expression, and would incorrectly perform the first-phase lookup from the lexical scope in which the instantiation of the fold-expression happened to be performed rather than doing the first-phase lookup from the context of the template definition.
I fixed this relatively recently (unfortunately not in time for the upcoming Clang 11 release), and the test case is now accepted by Clang trunk.