#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
withauto == B::BB
, ноB::foo
еще не была замечена , поэтомуA::foo<K>
создается экземпляр withK == B::BB
; при компиляцииtest2
тот жеmoo
экземпляр, который только что был скомпилирован и вызываетA::foo<B::BB>
совпадения , поэтому он снова вызывается; этот способB::foo
не вызывается. Если строка закомментирована, вместоmoo
этого создается экземпляр, когда видны обаA::foo<K>
иB::foo
, но последнее предпочтительнее, потому что это не шаблон. Это полная история?5. Да, я тоже это понимаю.