Подтвердить что ты не робот

Как я могу явно ссылаться на охватывающее пространство имен, когда существует встроенное пространство имен?

Пожалуйста, рассмотрите этот код:

#include <iostream>

namespace Foo{

    void ool()  // Version A
    {
        std::cout << "Foo::ool" << std::endl;
    }

    inline namespace Bar{
        void ool() // Version B
        {
            std::cout << "Foo::Bar::ool" << std::endl;
        }
    }
}


int main()
{
    Foo::ool();  // <- error
}

Как Clang, так и g++ корректно отмечают Foo::ool как неоднозначные. Я могу вызвать Foo::Bar::ool без проблем, но есть ли способ вызвать версию A без изменения ее объявления?

Я нашел людей в подобном положении, пытаясь понять, что происходит, но я не видел решения для этого случая.

Я в этой ситуации, потому что у меня есть проект, который включает объявление std::__1::pair и std::pair, выполненное в разных местах, причем std::__1 является встроенным пространством имен. Мне нужно, чтобы код явно указывал на std::pair. Есть ли решение для этого?

4b9b3361

Ответ 1

Я не думаю, что это возможно; от cppreference:

Квалифицированный поиск имени, который рассматривает охватываемое пространство имен, будет включать имена из встроенных пространств имен, даже если одно и то же имя присутствует в охватывающем пространстве имен.

Однако, похоже, вы на самом деле не находитесь в ситуации, о которой вы описываете, поскольку вы говорите, что два определения вытягиваются из разных файлов. Таким образом, вы "добавляете" более внешнее определение, чтобы иметь возможность называть его, когда вам это нужно:

#include <iostream>

// Equivalent of first include
namespace Foo{
    void ool()  // Version A
    {
        std::cout << "Foo::ool" << std::endl;
    }
}

const auto& foo_ool = Foo::ool;

// Equivalent of second include
namespace Foo{
    inline namespace Bar{
        void ool() // Version B
        {
            std::cout << "Foo::Bar::ool" << std::endl;
        }
    }
}

int main()
{
    foo_ool(); // Works
}

Если предмет, который вы хотите добавить в закладки, является типом, достаточно простой директивы using. Эквивалентный код для вас будет выглядеть следующим образом:

#include <my_first_include>

// bookmark code

#include <my_second_include>

// rest of the code

Ответ 2

Вы не можете однозначно обратиться к символу, определенному в охватывающем пространстве имен, после того, как было показано внутреннее пространство имен.

В частности, для случая, квалифицированный поиск в main по праву помечен как неоднозначный (как вы сказали сами). См. Последний пункт в cppreference:

Квалифицированный поиск имени, который рассматривает охватываемое пространство имен, будет включать имена из встроенных пространств имен, даже если одно и то же имя присутствует в охватывающем пространстве имен.


Тем не менее, как указывали другие комментаторы, , вы, вероятно, сталкиваетесь с проблемой конфигурации в вызове toolchain при попытке использовать std::pair.

Чтобы устранить проблему, вам нужно убедиться, что компилятор вызывается для компиляции кода С++ 11, который будет с флагом:

-std=c++11 или -std=c++0x в зависимости от вашей версии Clang/GCC

Чтобы дать дополнительный контекст:
Пространство имен inline - это функция С++ 11, в основном введенная для обеспечения управления версиями символов в библиотеках. Внедрение стандартной библиотеки С++ может затем определять разные версии символов в вложенных пространствах имен (с нестандартными именами), и в зависимости от запрашиваемой версии библиотеки при компиляции инструментальная цепочка определяет одно из этих вложенных пространств имен как встроенное. Кажется, вы используете версию библиотеки С++ 11 (так как она определяет некоторые символы, в частности pair, в inline namespace _1), поэтому с символами в встроенном пространстве имен на самом деле вы хотите.

Ответ 3

Я не думаю, что вы можете ссылаться на ool неоднозначно, когда в встроенном пространстве имен есть метод с тем же именем ool.

Но вы можете попробовать это;

#include <iostream>

namespace Foo{

    inline namespace A {
        void ool()  // Version A
        {
            std::cout << "Foo::ool" << std::endl;
        }
    }

    namespace Bar{
        void ool() // Version B
        {
            std::cout << "Foo::Bar::ool" << std::endl;
        }
    }
}


int main()
{
    Foo::ool();  // no error
}
  • Оберните методы в namespace Foo в namespace A, затем inline namespace A.
  • Удалить строку Bar.

Теперь, если вы сделаете вызов Foo::ool();, он вызовет inline A::ool()
Bar::ool может быть вызван Foo::Bar::ool