Пусть определён тип T, принадлежащий пространству имён A.
Пусть определена функция f() с параметром типа const T&, принадлежащая пространству имён B.
// Вариант 1namespace A
{
struct T;
}
struct A::T
{};
namespace B
{
void f(const A::T&);
}
void B::f(const A::T&)
{}
Вариант 1
Компиляторы clang, gcc и msvc подтверждают корректность вышеприведенного кода.
Теперь вместо FQN-имени типа T в объявлении и определении функции f() используем соответствующее using-объявление в пространстве имён B:
// Вариант 2namespace A
{
struct T;
}
struct A::T
{};
namespace B
{
using A::T;
void f(const T&);
}
void B::f(const T&)
{}
Вариант 2
Компиляторы clang, gcc и msvc подтверждают корректность вышеприведенного кода.
Теперь вместо using-объявления имени типа T используем директиву using namespace A в пространстве имён B:
// Вариант 3namespace A
{
struct T;
}
struct A::T
{};
namespace B
{
using namespace A;
void f(const T&);
}
void B::f(const T&)
{}
Вариант 3
Компиляторы clang и gcc подтверждают корректность вышеприведенного кода.
Компилятор msvc — нет.
Директива using namespace A по определению является холонимом using-объявления любого имени из пространства имён A, что и подтверждают компиляторы clang и gcc.
Следовательно, это не фича MSVC2015, а именно баг.
На свежем Webcompiler данный баг также воспроизводится.
Microsoft уже в курсе.
Просьба поддержать голосованием на их сайте актуальность данного бага.
Здравствуйте, tstalker, Вы писали:
T>Директива using namespace A по определению является холонимом using-объявления любого имени из пространства имён A, что и подтверждают компиляторы clang и gcc.
По определению она является using directive (7.3.4), во втором примере у тебя using declaration
T>Следовательно, это не фича MSVC2015, а именно баг. T>На свежем Webcompiler данный баг также воспроизводится.
Скорее расширение gcc и шланга, потому что 3.4.2-4
When considering an associated namespace, the lookup is the same as the lookup performed when the associated namespace is used as a qualifier (3.4.3.2) except that:
— Any using-directives in the associated namespace are ignored.
Могу ошибаться, но по-моему тут как раз этот пункт применяется.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Здравствуйте, Ops, Вы писали:
Ops>По определению она является using directive (7.3.4), во втором примере у тебя using declaration
Спасибо, кэп.
Не хотел разжёвывать очевидные вещи, но приходится:
Вариант 1: FQN.
Вариант 2: using declaration.
Вариант 3: using directive.
Согласно правилам языка C++ справедливо следующее неравенство:
using directive > using declaration > FQN
Именно с целью продемонстрировать справедливость неравенства и были реализованы все 3 варианта на 3 разных компиляторах.
gcc и clang отработали нормально все 3 варианта.
А msvc отработал нормально только 1 и 2 вариант, а на 3 споткнулся.
Вывод однозначен: это баг msvc.
Ops>Скорее расширение gcc и шланга
Бред.
Как раз msvc издавна печально известен более чем вольным трактованием стандарта языка, в чём неоднократно убеждались многие программисты, в том числе и я.
И на КЫВТ, и на других форумах полно такой инфы.
А вот gcc и clang довольно строго относятся к требованиям действующего стандарта и регулярно выпускают новые версии для приведения в соответствие оному.
А если и есть у них какие-то отличные от стандарта расширения, то все они строго документированы.
Ops>потому что 3.4.2-4
........... Ops>Могу ошибаться, но по-моему тут как раз этот пункт применяется.
Мимо кассы.
Вот вариант 4, не оставляющий никаких сомнений:
// Вариант 4namespace A
{
struct T{};
}
namespace B
{
using namespace A;
void f(const T&);
}
namespace B
{
void f(const T&)
{}
}
Вариант 4
О чудо!
Как и в 3 варианте, по-прежнему есть using directive и нет using declaration.
Но msvc вдруг прекрасно отработал.
Вывод однозначен: баг msvc, обнаруженный в 3 варианте.
Здравствуйте, tstalker, Вы писали:
T>Согласно правилам языка C++ справедливо следующее неравенство:
T>using directive > using declaration > FQN
Шито? Пункт стандарта, пожалуйста.
T>О чудо! T>Как и в 3 варианте, по-прежнему есть using directive и нет using declaration. T>Но msvc вдруг прекрасно отработал.
Потому что тут действуют другие правила name lookup, конкретно 3.4.1.2 T>Вывод однозначен: баг msvc, обнаруженный в 3 варианте.
Вывод однозначен: ты вместо стандарта пользуешься какими-то своими домыслами и гадаешь на реализациях компиляторов.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Здравствуйте, Ops, Вы писали:
Ops>Вывод однозначен: ты вместо стандарта пользуешься какими-то своими домыслами и гадаешь на реализациях компиляторов.
Жаль, беглым поиском по стандарту не нашёл эквивалентного примера, чтобы припереть тебя к стенке железобетонным аргументом — соответствующей ссылкой на стандарт.
А вообще складывается впечатление, что ты жирный тролль, отвергающий очевидные факты ради лулзов.
Интересно, если проверить мой код на 10 компиляторах, и все 10 подтвердят мою правоту, кроме msvc, тогда ты мне поверишь?
И всё же я попробую припереть тебя к стенке, тролль.
И никакой стандарт тебе не поможет.
Итак, даю мастер-класс укрощения троллей.
1. Допустим, и тип T, и функция f() принадлежат одному пространству имён:
namespace A
{
using T = int;
T f(T);
}
A::T A::f(T x)
{
return x;
}
Вопрос: на каком основании в определении функции f() тип T аргумента не требует fqn?
Ответ: на том, что в определении функции, принадлежащей пространству имён, область видимости данного пространства имён начинается сразу после fqn-имени функции.
Если воспользоваться суффиксным синтаксисом возвращаемого значения функции, то и тип функции f() также не требует fqn:
namespace A
{
using T = int;
T f(T);
}
auto A::f(T x) -> T
{
return x;
}
2. Теперь разнесём тип T и функцию f() по разным пространствам имён:
namespace A
{
using T = int;
}
namespace B
{
using namespace A;
T f(T);
}
// msvc errorauto B::f(T x) -> T
{
return x;
}
Компиляторы clang и gcc обработали код нормально, msvc — нет.
А почему собственно?
Ещё раз специально для троллей повторяем: в определении функции, принадлежащей пространству имён, область видимости данного пространства имён начинается сразу после fqn-имени функции.
Так может, компилятор msvc не считает тип T принадлежащим обоим пространствам имён A и B?
Проверим:
namespace A
{
using T = int;
}
namespace B
{
using namespace A;
T f(T);
}
// msvc okauto B::f(B::T x) -> B::T
{
return x;
}
Да нет — очень даже считает, иначе как бы работало fqn-имя типа B::T в определении функции f()?
Но тогда возникает закономерный вопрос: почему в законной области видимости пространства имён B компилятор msvc не видит законного имени типа T?
Ещё раз специально для троллей повторяем нудным голосом: в определении функции, принадлежащей пространству имён, область видимости данного пространства имён начинается сразу после fqn-имени функции.
При этом в объявлении функции f() тип T стоит вообще без всякой квалификации!
Что за двойные стандарты у компилятора msvc?
3. Резюме.
3.1. И объявление, и определение функции f() находятся в одной и той же области видимости пространства имён B — ваш К.О.
3.2. Тип T принадлежит обоим пространствам имён A и B (иначе B::T не работало бы).
3.3. Однако в объявлении функции f() компилятор msvc считает тип T принадлежащим пространству имён B, а в определении функции f() — нет.
3.4. Компиляторы clang и gcc таким маразмом не страдают.
4. Вывод. Вывод однозначен: это баг.
ЗЫ:
Ну давай, тролль, бухти мне про космические корабли процитируй мне соответствующие пункты стандарта...