Поиск по имени возвращаемого параметра

#c

#c

Вопрос:

Недавно студент спросил меня о проблеме компиляции. Ответ был довольно простым, но прямо сейчас я пытаюсь разобраться в причине. Простой пример:

 #include <iostream>
#include <vector>

struct MyStruct
{
    typedef std::vector<int> MyIntVector;

    MyIntVector CopyVector(MyIntVector constamp; vector);
};


MyStruct::MyIntVector MyStruct::CopyVector(MyIntVector constamp; vector)
^^^^^^^^
{
    MyIntVector vec;
    return vec;
}

int main(int /*argc*/, char** /*argv*/)
{
    MyStruct st;
}
  

Чтобы быть допустимым кодом c , возвращаемый параметр должен быть полностью определен. Большое спасибо за ответ и за то, чтобы порадовать компилятора / студента.

Но почему возвращаемое значение должно быть указано классом, а параметр функции — нет?

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

Ответ №1:

Структура грамматики такова, что возвращаемый тип не зависит от того, что объявлено, и можно объявить (но не определять) несколько объектов с одним и тем же типом. Это допустимый C :

 int f(int), g(int);
  

таким образом, наличие точной области видимости объявленных объектов, влияющих на поиск типа, было бы проблематичным. В

 id1 ns1::f(int), ns2::g(int);
  

где можно было бы искать id1?

Можно было бы добавить специальные правила для использования в определении функции (может быть только одно определение функции — чтобы не было двусмысленности -, но может быть несколько объектов по одному), но я не уверен, что такая возможность была рассмотрена, и я думаю, что добавленное усложнение не было бы компенсировано преимуществом.

Комментарии:

1. И может быть несколько объявлений функций, как вы показываете в своем примере. Для объявлений друзей это также действительно допустимо, семантически, я думаю: struct C { friend void A::f(), B::f(); }; .

Ответ №2:

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

Единственное, что может произойти в области пространства имен, — это объявление, и большинство объявлений C начинаются с имени типа, но в C. Помещение случайного, неопределенного идентификатора в область верхнего уровня в программе C объявляет его int с static видимостью.

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

C 11 решает проблему с синтаксисом завершающего возвращаемого типа:

 auto MyStruct::CopyVector(MyIntVector constamp; vector) -> MyIntVector {
  

Комментарии:

1. Но обратите внимание, что некоторые объявления не начинаются с имени типа. В частности, C::operator int() { } (функция преобразования), C::C() { } (конструктор) и C::~C() { } (деструктор) не начинаются с имени типа. Все они начинаются с функции именования идентификаторов декларатора.

2. @Johannes: Я подумал о том, чтобы подробнее остановиться на этом аргументе, поскольку существуют очевидные исключения, такие как namespace и спецификаторы класса хранения. Это определенно вышло неправильно. В любом случае, это всего лишь аргумент соломенного человека…