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