'g++ 11.2 cannot find an operator despite explicit using declaration

The following code fails to compile with g++ 11.2

#include <algorithm>
#include <array>
#include <utility>
#include <vector>

namespace tools {

template <std::size_t I = 0, class U, std::size_t N, class W, class F>
void op_1vec_impl(std::array<U, N>& a, const W& b, F&& f);

template <class U, std::size_t N, class W>
void operator/=(std::array<U, N>& a, const W& b) { op_1vec_impl(a, b, [](U& x, const W& y) { x /= y; }); }
  
// Implementation

template <std::size_t I, class U, std::size_t N, class W, class F>
void op_1vec_impl(std::array<U, N>& a, const W& b, F&& f)
{
  f(std::get<I>(a), b);
  if constexpr (I < (N - 1))
                 op_1vec_impl<I + 1>(a, b, std::forward<F>(f));

}

}

template <bool P>
void run();

int main(int argc, char *argv[])
{

  run<false>();
  return 0;
}

template <bool P>
void run()
{
      std::vector<std::array<double, 80>> vec(100);
      std::for_each(vec.begin(), vec.end(), [&](auto& el) { using tools::operator/=; el /= 4; });
}

Command line is:

g++ -c -std=c++17 -O3 -Wall -pedantic -o test_templates test_templates.cpp

The error is:

test_templates.cpp:41:89: error: no match for ‘operator/=’ (operand types are ‘std::array<double, 80>’ and ‘int’)
   41 |       std::for_each(vec.begin(), vec.end(), [&](auto& el) { using tools::operator/=; el /= 4; });

The code however compiles fine with g++ 10.1.x, and fails to compile from the version 11.? onwards. It also compiles with clang.

Test the code on godbolt.

Strangely, replacing the error line with

  std::for_each(vec.begin(), vec.end(), [&](auto& el) { using namespace tools; el /= 4; });

the code compiles.

Even more strangely, the code compiles if I replace the subroutine run() with a non-template one as in the following code!

#include <algorithm>
#include <array>
#include <utility>
#include <vector>

namespace tools {

template <std::size_t I = 0, class U, std::size_t N, class W, class F>
void op_1vec_impl(std::array<U, N>& a, const W& b, F&& f);

template <class U, std::size_t N, class W>
void operator/=(std::array<U, N>& a, const W& b) { op_1vec_impl(a, b, [](U& x, const W& y) { x /= y; }); }
  
// Implementation

template <std::size_t I, class U, std::size_t N, class W, class F>
void op_1vec_impl(std::array<U, N>& a, const W& b, F&& f)
{
  f(std::get<I>(a), b);
  if constexpr (I < (N - 1))
                 op_1vec_impl<I + 1>(a, b, std::forward<F>(f));

}

}

void run();

int main(int argc, char *argv[])
{

  run();
  return 0;
}

void run()
{
      std::vector<std::array<double, 80>> vec(100);
      std::for_each(vec.begin(), vec.end(), [&](auto& el) { using tools::operator/=; el /= 4; });
}

All in all, it looks like a compiler bug, but is it really so?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source