2013-11-18 6 views
1

Я пытаюсь перенести часть кода из boost::tuple в std::tuple, но я получаю некоторые странные ошибки: после того, как я призываю using namespace std (и никогда не boost), я ожидаю, неквалифицированный tie разрешить к std::tie. Однако это, похоже, терпит неудачу, если кортеж содержит указатель контейнера boost, например.C++ 11 галстука имя столкновение с усилением

#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 и увеличиваю 1.55.0. Считаете ли вы, что это ошибка с повышением? Или есть какая-то спецификация, которую мне не хватает?

+6

Это ADL. Используйте квалифицированное имя для обоих. – chris

+6

"после того, как я вызываю' using namespace std' "- *** NO *** – Xeo

+0

@Xeo: Я не в файле заголовка. I.e., IRL, определения fcn находятся в файлах заголовков без 'use', поэтому я помещаю его в' main() 'здесь. Кроме того, это не правило. –

ответ

4

Поиск сложный. Проблема, о которой говорили другие, - это зависящий от аргумента поиск или ADL. Правила ADL были добавлены, чтобы дать возможность определениям операторов в том же пространстве имен, что и типы, на которые они ссылаются, и включить поиск, чтобы найти эти операторы, когда они есть. Это было позже распространено на все другие функции в процессе стандартизации.

Проблема заключается в том, что tie(...) является вызовом функции. Компилятор попытается выполнить регулярный поиск из точки использования (внутри main) он перейдет в пространство имен. Директива using добавит ::std в поиск поиска, когда он попадает в корневое пространство имен (общий предок ::std и ::main). В этот момент, так как идентификатор решает функцию, ADL будет удар в.

ADL добавляет пространство имен связанные к аргументам вызова функции, которая в данном случае является boost:: (основные типов, как int не имеет ассоциированный Пространства имен). На этом этапе компилятор видит два объявления tie: std::tie и boost::tie, вызывая неоднозначность.

Как вы уже знаете, решение состоит в том, чтобы квалифицировать вызов на std::tie (что я бы посоветовал вам использовать даже без этой проблемы). Что касается комментария:

Если ADL позволяет решить увеличить :: галстук ... «моего удобства», а затем компиляция завершится неудачно, не следует, что быть ключом к компилятору, что он выбрал неправильную функцию ?!

Я не знаю, что точная ошибка вы получаете (я не использую импульс, и я не знаю, что это возможно перегрузки std::tie содержит). Если проблема действительно является одной из двусмысленностей, проблема в том, что компилятор не может разрешить идентификатор и не может продолжить процесс. В этот момент он останавливается и просит программиста его решить. Если ошибка заключается в том, что она уникально выбрана boost::tie, и позже она не удалась в присваивании, это означает, что theres является перегрузкой boost::tie, которая лучше соответствует std::tie, и это было выбрано. Позднее назначение с std::tuple может быть неудачным, но компилятор не может знать, была ли проблема во время поиска, или это само присваивание (вы намеревались назначить эту переменную? Может быть, другой?), Так что снова это не удается и рассказывает вам, в чем проблема.

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

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

+0

Вы правы, ошибка, которую я получаю (к сожалению, они недостаточно лаконичны для публикации, я люблю C++, за исключением связанных с шаблоном этих ошибок ...) было о задаче 'tuple'. Поэтому 'tie' разрешает' boost :: tuples :: tie', который создает 'boost :: tuples :: tuple' lvalue, на котором' operator = 'работает, с' std :: tuple' как rvalue, и что генерирует ошибку. –

+0

Re: компиляция, перемещающаяся только вперед: из того, что я собираю, целью ADL является предоставление краткого синтаксиса для операторов, таких как 'std :: string' дополнение. Странно, что в этом случае ADL требует менее сжатого синтаксиса. Я все еще думаю, что компилятор может быть немного умнее: все, что ему нужно сделать, это понять, что правильное разрешение имени 'tie' в этой точке должно также допускать применение такого типа' operator = (const std :: tuple &) '. Прошло много лет с тех пор, как я разработал макет-компилятор для проекта курса, возможно, gcc более сложный, чем этот: D –

+1

@mmd: Цель ADL ** не ** делает код более кратким, он был разработан, чтобы позволить поиск для поиска операторов (для которых вы ** не можете ** предоставить квалификацию в целом) для типов, определенных в разных пространствах имен. Вы можете использовать его, чтобы избежать квалификации, но это побочный эффект того, что комитет выдвинул подход Андрея к * всем * функциям, а не только операторам (это было первоначальное намерение). Причина, по которой вы * не можете * квалифицировать операторов, заключается в том, что синтаксис для квалифицированного вызова зависит от того, как определяется оператор: 'ns :: operator + (a, b)' vs. 'a.operator + (b)' –

 Смежные вопросы

  • Нет связанных вопросов^_^