Как я могу явно ссылаться на охватывающее пространство имен, когда существует встроенное пространство имен?
Пожалуйста, рассмотрите этот код:
#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
. Есть ли решение для этого?
Ответы
Ответ 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