Как я могу явно ссылаться на вмещающее пространство имен, когда существует встроенное пространство имен?
Пожалуйста, рассмотрите этот код:
#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
}
- Обернуть методы в
namespace Foo
вnamespace A
затемinline
namespace A
, - Удалить встроенный из
Bar
,
Теперь, если вы позвоните Foo::ool();
это вызовет inline A::ool()
Bar::ool
может быть вызван Foo::Bar::ool