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

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

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

24

Решение

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

Другие решения

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

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

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


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

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

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

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

5

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

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

2
По вопросам рекламы [email protected]