MSVC - 在通用 lambda 的调用者中使用命名空间指令泄漏到 lambda 的主体中

MSVC - Using namespace directive in caller of generic lambda leaks into the lambda's body

考虑以下玩具代码:

#include <boost/hana/transform.hpp>
#include <range/v3/view/transform.hpp>

auto constexpr f = [](auto) {
    using namespace ranges::views;
    auto xxx = transform;
};

void caller() {
    using boost::hana::transform;
    f(1);
}

它用 GCC 和 MS 的编译器编译得很好,这意味着 using boost::hana::transform; 不会影响 f 主体中可用的名称,因此 xxxranges::views::transform.

另一方面,如果我将 using boost::hana::transform; 更改为 using namespace boost::hana;,则 Visual Studio 声称 f 正文中的 transform 是模棱两可的名字.

这是 GCC 中的错误还是 Visual Studio?这是一个已知的错误吗?这是因为什么?

这是一个小例子 (run it):

#include <boost/hana/transform.hpp>
#include <range/v3/view/transform.hpp>

auto constexpr f = [](auto) {
    using namespace ranges::views;
    auto xxx = transform;
};

void caller() {
#if 1
    using namespace boost::hana;
#else
    using boost::hana::transform;
#endif
    f(1);
}

这是一个 MSVC 错误,与 generic lambdas 有关。一个最小的例子是

void foo() {}

namespace B {
   void foo() {}
}

auto moo = [](auto) {
   foo();
};

int main() {
   using namespace B;
   moo(1);
}

它使用 c++17 和 c++20 设置重现。

已知 MSVC 对模板实例化和两阶段名称查找的处理不一致。许多这些错误在最新版本的编译器中得到修复,但显然不是全部。这里,在实例化 moo 之后,名称 foo 显然是在实例化上下文中查找的。这不应该发生,因为它不是从属名称。


相关示例:

#include <iostream>

namespace A{
   template <typename K>
   int foo(K) { return 1; }
}

using namespace A;
namespace B {
   struct BB {};
}

auto moo = [](auto i) {
   return foo(i);
};

void test1() {
   std::cout << moo(B::BB{}); // Comment this and see how the output changes
}

namespace B {
   int foo(BB) { return 2; }
}

void test2() {
   std::cout << moo(B::BB{});
}

int main() {
    test1();
    test2();
}

(查看 here 的实际效果。)