Столкновение имен 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 Возможно, произошел сбой, но компилятор не может знать, была ли проблема во время поиска, или это было само присвоение (вы намеревались присвоить эту переменную? Может быть, другое?), так что он снова завершается неудачно и сообщает вам, в чем проблема.

Обратите внимание, что в целом процесс компиляции всегда движется вперед, компилятор не отступает, чтобы дважды угадать свои собственные решения*. Существует набор правил, и эти правила применяются на каждом этапе. Если есть неоднозначность, компиляция останавливается, если нет, тогда существует единственный лучший кандидат, и этот момент решается, переходя к следующему. Попытка вернуться к отмененным решениям превратила бы процесс компиляции во что-то мучительно медленное (число путей, которые можно было бы использовать, было бы экспоненциальным).

* Как всегда, есть некоторые исключения, но это просто исключения, особенно при разрешении перегрузки, если шаблон выбран как лучший кандидат, но замена аргументов типа не удалась, он отбрасывается и выбирается следующий лучший кандидат.

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