Столкновение имен C++11 с бустом
Я пытаюсь перенести некоторый код из boost::tuple
в std::tuple
но я получаю некоторые странные ошибки: после того, как я вызываю using namespace std
(и никогда boost
) Я ожидаю неквалифицированного tie
разрешить std::tie
, Однако, похоже, что это не работает, когда кортеж содержит указатель контейнера наддува, например.
#include <tuple>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
#ifdef USE_STD
#define TIE std::tie
#else
#define TIE tie
#endif
typedef boost::multi_index_container<
int,
boost::multi_index::indexed_by<
boost::multi_index::ordered_non_unique<
boost::multi_index::identity<int>
>
>
> Set;
std::tuple< int, int* > make_i_ptr();
std::tuple< int, Set* > make_set();
int main()
{
using namespace std;
int i;
int* i_ptr;
Set* set_ptr;
tie(i, i_ptr) = make_i_ptr();
TIE(i, set_ptr) = make_set();
return 0;
}
Если я скомпилирую с g++ -std=c++0x -c test.cpp -DUSE_STD
, все хорошо. Однако без -D USE_STD
Я получаю ошибки компиляции, предлагающие g++
пытается использовать boost::tuples::tie
, Я использую G ++ 4.8.1 и Boost 1.55.0. Как вы думаете, это ошибка с бустом? Или мне не хватает какой-то спецификации?
1 ответ
Поиск сложен. Проблема, как уже упоминали другие, это Аргумент-зависимый поиск или ADL. Правила для ADL были добавлены, чтобы разрешить определение операторов в том же пространстве имен, что и типы, к которым они относятся, и разрешить поиск, чтобы найти эти операторы при их наличии. Позднее это было распространено на все другие функции в процессе стандартизации.
Проблема здесь в том, что tie(...)
это вызов функции. Компилятор будет пытаться регулярно искать с точки зрения использования (внутри main
) он переместится во вложенное пространство имен. Директива using добавит ::std
в поиске поиска, когда он попадает в корневое пространство имен (общий предок ::std
а также ::main
). В этот момент, поскольку идентификатор разрешается в функцию, ADL включается.
ADL добавляет пространства имен, связанные с аргументами вызова функции, который в этом случае boost::
(основные типы, такие как int
не имеют связанных пространств имен). На этом этапе компилятор видит два объявления tie
: std::tie
а также boost::tie
, вызывая двусмысленность.
Как вы уже знаете, решение состоит в том, чтобы квалифицировать вызов std::tie
(который я бы посоветовал использовать даже без этой проблемы). По поводу комментария:
Если ADL разрешит повысить::tie для... "моего удобства", и компиляция завершится неудачно, разве это не должно быть подсказкой компилятору, что он выбрал неправильную функцию?!
Я не знаю, какая именно ошибка вы получаете (я не использую повышение, и я не знаю, какие возможные перегрузки std::tie
это содержит). Если проблема действительно в двусмысленности, проблема в том, что компилятор не может разрешить идентификатор и не может продолжить процесс. В этот момент он останавливается и просит программиста разрешить его. Если ошибка в том, что он однозначно выбран boost::tie
и позже это не удалось в назначении, это означает, что есть перегрузка boost::tie
это лучше, чем std::tie
и это было выбрано. Позже назначение от std::tuple
Возможно, произошел сбой, но компилятор не может знать, была ли проблема во время поиска, или это было само присвоение (вы намеревались присвоить эту переменную? Может быть, другое?), так что он снова завершается неудачно и сообщает вам, в чем проблема.
Обратите внимание, что в целом процесс компиляции всегда движется вперед, компилятор не отступает, чтобы дважды угадать свои собственные решения*. Существует набор правил, и эти правила применяются на каждом этапе. Если есть неоднозначность, компиляция останавливается, если нет, тогда существует единственный лучший кандидат, и этот момент решается, переходя к следующему. Попытка вернуться к отмененным решениям превратила бы процесс компиляции во что-то мучительно медленное (число путей, которые можно было бы использовать, было бы экспоненциальным).
* Как всегда, есть некоторые исключения, но это просто исключения, особенно при разрешении перегрузки, если шаблон выбран как лучший кандидат, но замена аргументов типа не удалась, он отбрасывается и выбирается следующий лучший кандидат.