2

Consider this piece of code:

#include <iostream>
#include <sstream>
#include <iterator>
#include <vector>
#include <string>
    
int main() {
    std::istringstream ss("abcabc abc a b e");
    std::vector<std::string> words(std::istream_iterator<std::string>(ss), std::istream_iterator<std::string>());
    std::string deciphered;
    int shift = 5;
    for (size_t i = 0; i < shift; i++)
    {
        for (size_t j = 0; i + j < words.size(); j += shift)
        {
            deciphered += words[i + j];
        }
    }
}

Basically, I want to split words and store them to my words array. But I get compile errors:

main.cpp: In function 'int main()':
main.cpp:14:40: error: request for member 'size' in 'words', which is of non-class type 'std::vector<std::__cxx11::basic_string<char> >(std::istream_iterator<std::__cxx11::basic_string<char> >, std::istream_iterator<std::__cxx11::basic_string<char> > (*)())'
   14 |       for (size_t j = 0; i + j < words.size(); j += shift)
      |                                        ^~~~
main.cpp:16:33: warning: pointer to a function used in arithmetic [-Wpointer-arith]
   16 |        deciphered += words[i + j];
      |                                 ^
main.cpp:16:33: error: invalid conversion from 'std::vector<std::__cxx11::basic_string<char> > (*)(std::istream_iterator<std::__cxx11::basic_string<char> >, std::istream_iterator<std::__cxx11::basic_string<char> > (*)())' to 'char' [-fpermissive]
   16 |        deciphered += words[i + j];
      |                      ~~~~~~~~~~~^
      |                                 |
      |                                 std::vector<std::__cxx11::basic_string<char> > (*)(std::istream_iterator<std::__cxx11::basic_string<char> >, std::istream_iterator<std::__cxx11::basic_string<char> > (*)())
In file included from c:\mingw\lib\gcc\mingw32\9.2.0\include\c++\string:55,
                 from c:\mingw\lib\gcc\mingw32\9.2.0\include\c++\bits\locale_classes.h:40,
                 from c:\mingw\lib\gcc\mingw32\9.2.0\include\c++\bits\ios_base.h:41,
                 from c:\mingw\lib\gcc\mingw32\9.2.0\include\c++\ios:42,
                 from c:\mingw\lib\gcc\mingw32\9.2.0\include\c++\ostream:38,
                 from c:\mingw\lib\gcc\mingw32\9.2.0\include\c++\iostream:39,
                 from main.cpp:1:
c:\mingw\lib\gcc\mingw32\9.2.0\include\c++\bits\basic_string.h:1186:25: note:   initializing argument 1 of 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>& std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::operator+=(_CharT) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]'
 1186 |       operator+=(_CharT __c)
      |                  ~~~~~~~^~~

Judging by the errors, my variable words was identified as a function.

I'm so confused, what's the reason for this behavior? And how do I fix it?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Learpcs
  • 282
  • 3
  • 10
  • 1
    Does this answer your question? [A confusing detail about the Most Vexing Parse](https://stackoverflow.com/questions/7007817/a-confusing-detail-about-the-most-vexing-parse) – BoP Dec 20 '21 at 22:14

2 Answers2

4

This is what is known as most vexing parse, in this case you should use the braced initialization syntax which will let the compiler know you are trying to construct an instance of a class instead of declaring a function.

i.e std::vector<int> a{} instead of std::vector<int> a()

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
Moshe Rabaev
  • 1,892
  • 16
  • 31
1

According to the rules of the C++ language, in this line:

std::vector<std::string> words(std::istream_iterator<std::string>(ss), std::istream_iterator<std::string>());

It is a declaration of a new identifier words, as you intended. However, everything else goes unintended:

words is a function, returning std::vector<std::string> and taking two parameters both of type std::istream_iterator<std::string>. The first parameter is named ss and the second parameter is unnamed.

Throughout multiple C++ versions, there have been a variety of ways to force the compiler to see this as the declaration and initialization of a variable. The easiest one, added in C++11, is what @Moshe suggested: Use braces not parenthesis to designate the initializers.

std::vector<std::string> words{std::istream_iterator<std::string>(ss), std::istream_iterator<std::string>()};
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720