Самый неприятный синтаксический анализ с доступом к массиву
При взгляде на некоторый код С++ 03 я нашел экземпляр наиболее неприятного разбора, который смутил меня:
#include <sstream>
#include <string>
int main(int, char** argv)
{
std::stringstream ss(std::string(argv[0]));
}
живой пример в wandbox
В приведенном выше фрагменте ss
является объявлением функции, которая принимает std::string*
и возвращает std::stringstream
.
Как std::string(argv[0])
анализируется как std::string*
?
Интуитивно я думал, что argv[0]
был однозначно доступ к argv
.
Ответы
Ответ 1
Причина в том, что в контексте объявления функции компилятор интерпретирует std::string(argv[0])
как std::string argv[0]
, то есть объявление массива нулевого размера как параметр функции с именем argv
(затеняет argv
от main
, так как это другая область), которая затем эквивалентна указателю с помощью распада массива-указателя.
Следовательно, std::stringstream ss(std::string(argv[0]));
означает то же самое, что std::stringstream ss(std::string* argv);
Изменить: поскольку он был правильно аннотирован в комментариях, объявления массива нулевого размера недействительны в С++, что делает программу плохо сформированной. При компиляции этого кода с флагами -pedantic
(GCC и clang) будут выданы предупреждения. Visual Studio даже создает ошибку компиляции. Для любого другого индекса массива, кроме 0, аргумент выше, тем не менее, сохраняется.
Ответ 2
Я считаю, что это следует из принципа синтаксиса "синтаксис объявления как принцип синтаксиса выражения", и тот факт, что параметры "массива" являются указателями.
Следующие объявления массива эквивалентны:
int x[1];
int (x)[1];
int (x[1]);
более или менее, потому что x[a]
, (x)[a]
и (x[a])
являются эквивалентными выражениями.
Таким образом,
std::stringstream ss(std::string(argv[0]))
<=>
std::stringstream ss(std::string argv[0])
<=>
std::stringstream ss(std::string* argv)