C ++: влияет ли порядок использования объявления и директивы на выбор? - PullRequest
3 голосов
/ 14 марта 2019

Ниже приведен пример кода

#include <iostream>
using namespace std;


namespace A {
    void f() { cout << "a" << endl; }
}
namespace B {
    void f() { cout << "b" << endl; }
}
namespace C {
    using namespace A;
    using namespace B;
    using A::f;
}
namespace D {
    using A::f;
    using namespace A;
    using namespace B;
}
int main()
{
    C::f();
    D::f();
}

При печати в Visual Studio 2015 дважды выводится «a». Это поведение определяется стандартом или это конкретная реализация?

Ответы [ 2 ]

4 голосов
/ 14 марта 2019

Это определяется стандартом (такие вещи всегда есть). Главное, что нужно понять, это то, что различные строки using namespace не влияют на вашу программу.

using namespace Foo - это «директива using», которая влияет на поиск имени, который выполняется кодом в области видимости. То есть, если какая-то более поздняя функция в вашем блоке namespace C {} попытается найти какой-либо объект с именами foo, A и B, он окажется в числе мест, где компилятор будет искать, чтобы найти foo. Напротив, это не изменило бы, где компилятор будет выглядеть, если бы более поздний код ссылался на C::foo. Порядок двух последовательных using namespace с в одном блоке не имеет значения, поскольку каждый из них имеет полный эффект до конца блока.

Причина, по которой вы можете найти f в C или D, заключается в "объявлении об использовании" using A::f. Объявление-использование, в отличие от директивы-использования, приводит к тому, что имя вводится в область видимости, так что другой код может ссылаться на имя как находящееся внутри этой области.

4 голосов
/ 14 марта 2019

Следующие два абзаца из cppreference.com должны объяснять поведение:

Директива Using [using namespace A;] не добавляет никаких имен в декларативную область, в которойоно появляется (в отличие от объявления using [using A::f;]) и, таким образом, не препятствует объявлению идентичных имен.

Директивы using транзитивны для целей неквалифицированного поиска: если область содержит использование-directive, который назначает namespace-name, которое само содержит директиву using для некоторого namespace-name-2, эффект таков, как если бы директивы using из второго пространства имен появлялись в первом.Порядок, в котором происходят эти транзитивные пространства имен, не влияет на поиск имен.

Проще говоря: using A::f; такой, как если бы вы объявили функцию в этом пространстве имен.using namespace A; просто заставляет поиск по typename вести себя так, как если бы текущее пространство имен (C или D) в вашем случае было пространствами имен внутри A.

Это похоже на то, как

namespace A {
    void f() { cout << "a" << endl; }

    namespace B {
        void f() { cout << "b" << endl; }
    }
}

и

namespace A {
    namespace B {
        void f() { cout << "b" << endl; }
    }

    void f() { cout << "a" << endl; }
}

эквивалентны.

...