Search code examples
c++vectorcompiler-errorsc++14push-back

Pushing a string to a private member vector


I have a std::vector<std::string> tileSet_ as a member variable of a class. In the constructor of said class I call the function

void MapWindow::shuffleTiles() const
{
  std::vector<std::pair<std::string, unsigned>> tileAmounts = {
    {"a", 2}, {"b", 4}, {"c", 1}, {"d", 4},
    {"e", 5}, {"f", 2}, {"g", 1}, {"h", 3},
    {"i", 2}, {"j", 3}, {"k", 3}, {"l", 3},
    {"m", 2}, {"n", 3}, {"o", 2}, {"p", 3},
    {"q", 1}, {"r", 3}, {"s", 2}, {"t", 1},
    {"u", 8}, {"v", 9}, {"w", 4}, {"x", 1}
  };

  int tileN = 0;
  for (std::vector<std::pair<std::string, int>>::size_type i = 0;
    i < tileAmounts.size();i++) {
    tileN += tileAmounts.at(i).second;
  }

  // only used once to initialise (seed) engine
  std::random_device rd;
  // random-number engine used (Mersenne-Twister in this case)
  std::mt19937 rng(rd());
  // guaranteed unbiased
  std::uniform_int_distribution<int> uni(0,tileAmounts.size() - 1);

  for (int i = 0; i < tileN; i++) {
    auto random_integer = uni(rng);
    //qDebug() << i << ":" << random_integer;
    std::cout << i
              << ":"
              << tileAmounts.at(random_integer).first
              << ":"
              << tileAmounts.at(random_integer).second
              << std::endl
              << std::endl;

    while (tileAmounts.at(random_integer).second < 1) {
      std::cout << "Reshuffling "
               << tileAmounts.at(random_integer).first
               << ":"
               << tileAmounts.at(random_integer).second
               << std::endl;
      random_integer = uni(rng);
    }

    std::string s = tileAmounts[random_integer].first;
    std::cout << s
              << std::endl;

    tileSet_.push_back(s);
    tileAmounts.at(random_integer).second -= 1;
  }

  for (std::vector<std::string>::size_type i = 0;
    i < tileSet_.size();i++) {
    std::cout << tileSet_.at(i)
              << std::endl;
  }
}

which at the very end attempts to push back a randomly picked string from a pair contained in the vector tileAmounts into the memeber vector. For some reason, this raises the error

no matching member function call to 'push_back'

Why does this happen. I'm taking the vector to be pushed back from a std::pair, but surely that shouldn't be causing any type mismatches? A std::string in a std::pair contained in a std::vector is still a std::string, no?


Solution

  • Took me a while to get it all building (with some guesses).

    The problem is that the method is marked const. Thus you are not allowed to call any mutating functions on members (ie you can not call none const member functions or none const member functions on any member variables).

     void MapWindow::shuffleTiles() const
                                    ^^^^^
     ...
         tileSet_.push_back(s);  // Attempt to mutate the state of the object.
    

    This is explained in greate detail in the error message generated by the compiler:

    t2.cpp:61:14: error: no matching member function for call to 'push_back'
        tileSet_.push_back(s);
        ~~~~~~~~~^~~~~~~~~
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:712:36: note: candidate function not viable: 'this' argument has type
          'const std::vector<std::string>' (aka 'const vector<basic_string<char, char_traits<char>, allocator<char> > >'), but method is not marked const
        _LIBCPP_INLINE_VISIBILITY void push_back(const_reference __x);
                                       ^
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/vector:715:36: note: candidate function not viable: 'this' argument has type
          'const std::vector<std::string>' (aka 'const vector<basic_string<char, char_traits<char>, allocator<char> > >'), but method is not marked const
        _LIBCPP_INLINE_VISIBILITY void push_back(value_type&& __x);
    

    If you go to the end of the line it says: "but method is not marked const"

    Deciphering line:

    note: candidate function not viable: 'this' argument has type
    'const std::vector', but method is not marked const
    void push_back(const_reference __x);

    note: candidate function not viable: 'this' argument has type
    'const std::vector', but method is not marked const
    void push_back(value_type&& __x);