Псевдонимы типов и ссылки на самих себя

Например, односвязный узел списка может быть определен следующим образом.

namespace example_part1
{
    class node
    {
        node * next;
        int value;
    }
}

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

Теперь, почему мне не разрешено это делать

namespace example_part2
{
    using node = std::pair<example_part2::node *, int>;
}

?

Я знаю, что это кажется глупым примером, но я хочу узнать больше о причине, почему это не скомпилируется. На самом деле у меня похожая ситуация, где это может быть полезно (не с std::pair). Кроме того, предположим, что эти два сегмента кода принадлежат разным программам, т. е. у меня нет пользовательского класса узла, а также пары псевдонимов узла в одной и той же программе.


person Konrad    schedule 28.04.2017    source источник
comment
узел будет настраиваемым классом и std::pair одновременно?   -  person Millie Smith    schedule 29.04.2017
comment
@MillieSmith, пожалуйста, посмотрите мое редактирование (дополнение) к основному вопросу   -  person Konrad    schedule 29.04.2017
comment
Итак, судя по вашему редактированию, using node = std::pair<node *, int>; совсем один? Например, node еще не определено? Как он должен знать настоящий тип? Когда заканчивается рекурсия?   -  person Millie Smith    schedule 29.04.2017
comment
@MillieSmith так же, как он знает фактический тип в случае класса?   -  person Konrad    schedule 29.04.2017
comment
Рекурсия заканчивается, когда вы используете классы с указателями. Вы можете создать узел с нулевым указателем. Как построить std::pair‹node *, int›? std::pair<std::pair<std::pair<....., int> *, int> *, int>   -  person Millie Smith    schedule 29.04.2017
comment
Если предположить, что using node = std::pair<node *, int>; нужно объявить внутри struct node, то это чепуха. Вы не можете назвать какую-либо сущность с тем же именем, что и $the class-name внутри $the class' body.   -  person WhiZTiM    schedule 29.04.2017
comment
@WhiZTiM, в последнем абзаце я сказал, что это два совершенно разных сегмента кода. Предположение, которое вы сделали, неверно.   -  person Konrad    schedule 29.04.2017
comment
Бесконечно рекурсивные определения редко бывают правильными.   -  person Donnie    schedule 29.04.2017
comment
@KonradKapp, хорошо. Только что увидел вашу правку. ... У вас конфликт имен. Вы можете просто использовать другое имя или воспользоваться услугами namespaces для их устранения неоднозначности.   -  person WhiZTiM    schedule 29.04.2017
comment
@WhiZTiM спасибо, только что отредактировал.   -  person Konrad    schedule 29.04.2017
comment
Обратите внимание, что на странице en.cppreference.com/w/cpp/language/type_alias абстрактный декларатор или любой другой действительный идентификатор типа (который может ввести новый тип, как указано в идентификаторе типа). Идентификатор типа не может прямо или косвенно ссылаться на идентификатор.   -  person Donnie    schedule 29.04.2017
comment
@ Донни, сделай это ответом, и я приму его. Спасибо.   -  person Konrad    schedule 29.04.2017


Ответы (2)


Обратите внимание, что в тип-псевдоним

[идентификатор_типа является] абстрактным декларатором или любым другим допустимым идентификатором типа (который может вводить новый тип, как указано в идентификаторе типа). Идентификатор типа не может прямо или косвенно ссылаться на идентификатор.

По сути, псевдонимы не могут быть рекурсивными.

person Donnie    schedule 28.04.2017
comment
(за исключением, очевидно, того, что я должен был просто опубликовать ответ в начале вместо комментария с ответом.) - person Donnie; 29.04.2017

При обращении к спецификации объявлений псевдонимов типов в cppreference идентификатор типа не должны прямо или косвенно относиться к вводимому имени:

использование идентификатора attr(необязательно) = type-id ; идентификатор — имя, которое вводится этим объявлением, которое становится либо именем типа, список-параметров-шаблона — список параметров шаблона, как в объявлении шаблона идентификатор-типа — абстрактный декларатор, либо любым другим допустимым идентификатором-типом (который может ввести новый type, как указано в type-id). Идентификатор типа не может прямо или косвенно ссылаться на идентификатор. Обратите внимание, что точка объявления идентификатора находится в точке с запятой после идентификатора типа.

Что касается пространств имен, обратите внимание, что node в std::pair<node *, int> не относится к node пространства имен example_part1 и, следовательно, остается неопределенным именем типа.

person Stephan Lechner    schedule 28.04.2017
comment
Есть ли причины отрицательных голосов, которые помогают мне улучшить ответ? - person Stephan Lechner; 29.04.2017
comment
Вы совершенно неправильно поняли вопрос. В последнем абзаце я сказал, что эти два сегмента кода совершенно разные, как будто они из разных программ. Затем я изменил код, чтобы они находились в разных пространствах имен, как было предложено в комментариях, для дальнейшего уточнения. В любом случае, спасибо, что заметили ошибку в моем редактировании. - person Konrad; 29.04.2017
comment
Я предполагаю, что это потому, что он, вероятно, хочет, чтобы node * в pair создавало указатель на псевдоним, который он создает, а не указатель на node в другом пространстве имен. - person Nicol Bolas; 29.04.2017
comment
Это не отвечает на вопрос, который он задает. - person Donnie; 29.04.2017
comment
@StephanLechner В конце концов, хороший ответ, но другой человек получил его первым (в разделе комментариев к исходному вопросу), прежде чем вы изменили его на текущую версию. Поэтому вместо этого принят другой ответ - person Konrad; 29.04.2017