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

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

#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 в явном виде. Есть ли решение для этого?

3 ответа

Решение

Я не думаю, что это возможно; из 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

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

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

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


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

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

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

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

Я не думаю, что вы можете сослаться 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
}
  1. Обернуть методы в namespace Foo в namespace A затем inlinenamespace A,
  2. Удалить встроенный из Bar,

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

Другие вопросы по тегам