Векторный конструктор с двумя параметрами анализируется как объявление функции - PullRequest
5 голосов
/ 19 января 2012

Рассмотрим этот пример:

#include <iostream>
#include <string>
#include <vector>
#include <iterator>

int main()
{
    std::string sen = "abc def ghi jkl";
    std::istringstream iss(sen);

    std::vector<std::string>    // declaration in question
    vec(std::istream_iterator<std::string>(iss),
        std::istream_iterator<std::string>());

    std::copy(vec.begin(), vec.end(),
              std::ostream_iterator<std::string>(std::cout, "\n"));
}

Компилятор выдает ошибку при вызове std::copy

request for member 'begin' in 'vec', which is of non-class type...

Я могу обойти ошибку, как это:

std::istream_iterator<std::string> it_begin(iss);
std::istream_iterator<std::string> it_end;
std::vector<std::string> vec(it_begin, it_end);

или поместив скобки вокруг каждого параметра, например:

std::vector<std::string>
vec((std::istream_iterator<std::string>(iss)),
    (std::istream_iterator<std::string>()));

или даже с новой унифицированной инициализацией в C ++ 11:

std::vector<std::string> vec { /*begin*/, /*end*/ };

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

1 Ответ

9 голосов
/ 19 января 2012

Это все еще самый неприятный анализ.

std::vector<std::string>                     // return type
vec(                                         // function name
    std::istream_iterator<std::string>(iss), // param 1: an iterator called (iss), or just iss
    std::istream_iterator<std::string>()     // param 2: unnamed function 
);                                           //          returning iterator

Джорджи говорит:

<tomalak> << ETYPE_DESC(vec); std::vector<std::string> vec(std::istream_iterator<std::string>(iss), std::istream_iterator<std::string>());
<geordi> lvalue function taking a istream_iterator<string, char, char_traits<char>, long> , a pointer to a nullary function returning a istream_iterator<string, char, char_traits<char>, long> , and returning a vector of strings

Суть в том, что имена ваших параметров могут иметь круглые скобки вокруг них (т.е. iss & rarr; (iss)) без изменения семантики объявления. Иногда.

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


Если это поможет, также подумайте:

void foo(int (x)) {
   cout << x;
}

int main() {
   foo(42);
}

Вывод 42.

...