MSVC — директива пространства имен, используемая в вызывающем объекте для общих утечек лямбды в тело лямбды

#c #visual-studio #compiler-errors #c 17 #language-lawyer

Вопрос:

Рассмотрим следующий код игрушки:

 #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 теле, так что это однозначно xxx ranges::views::transform .

С другой стороны, если я изменюсь using boost::hana::transform; на using namespace boost::hana; , то Visual Studio утверждает, что transform тело in f -это неоднозначное имя.

Это ошибка в GCC или Visual Studio? Это известная ошибка? С чем это связано?

Вот небольшой пример (запустите его):

 #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);
}
 

Комментарии:

1. Какие версии? Существует довольно много версий как gcc, так и cl.exe которые поддерживают c 17

2. @n.1.8e9-где моя доля., вы нажали на ссылку внизу моего вопроса?

3. @Mgetz, нажмите на ссылку внизу вопроса.

4. @Enlico вам необходимо включить эту информацию в свой вопрос. Links die 😉

Ответ №1:

Это ошибка MSVC, которая связана с общими лямбдами. Минимальным примером является

 void foo() {}

namespace B {
   void foo() {}
}

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

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

Он воспроизводится с настройками c 17 и c 20.

Известно, что MSVC имеет несоответствующую обработку создания экземпляра шаблона и двухфазный поиск имени. Многие из этих ошибок исправлены в последних версиях компилятора, но, по-видимому, не все. Здесь, после moo создания экземпляра, имя foo , по-видимому, просматривается в контексте создания экземпляра. Этого не должно произойти, потому что это не зависимое имя.

Комментарии:

1. Можете ли вы привести пример того, когда поиск в контексте создания экземпляра является правильным? В этом случае я думаю, что передача moo параметра s в foo ( foo foo(int) например , оба объявлены как) создаст foo зависимое имя; но в этом случае, как вызов будет неоднозначным?

2. Я не знаю, существует ли контекст, который может ввести эту точную двусмысленность. «Для вызова функции, в которой постфиксное выражение является зависимым именем, функции-кандидаты определяются с использованием обычных правил поиска из контекста определения шаблона» (temp.dep.кандидат) (примечание, а не из контекста создания экземпляра). Подобные неясности могут быть и для нефункциональных функций, но я их не искал.

3. Однако при выполнении ADL поиск выполняется как в контексте определения, так и в контексте создания экземпляра, см. Этот пример (прокомментируйте отмеченную строку и посмотрите, что произойдет).

4. Что это такое?! Правильно ли я понимаю?: при компиляции test1 некомментированная строка запускает создание экземпляра moo with auto == B::BB , но B::foo еще не была замечена , поэтому A::foo<K> создается экземпляр with K == B::BB ; при компиляции test2 тот же moo экземпляр, который только что был скомпилирован и вызывает A::foo<B::BB> совпадения , поэтому он снова вызывается; этот способ B::foo не вызывается. Если строка закомментирована, вместо moo этого создается экземпляр, когда видны оба A::foo<K> и B::foo , но последнее предпочтительнее, потому что это не шаблон. Это полная история?

5. Да, я тоже это понимаю.