fold expression and function name lookup

落爺英雄遲暮 提交于 2021-02-20 19:58:35


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.