0

I am trying to debug this code from my supervisor and I'm new to C++.

I found a few similar no matching function for call to questions, which gave me ideas what the problem might be but was not able to solve it.

I have listed my thoughts below the error message and relevant function.

Error message:

In function ‘int main(int, char**)’:
distanceMatrixToSageGraph.c:104:43: error: no matching function for call to 
‘std::vector<std::vector<int>>::push_back(std::vector<std::__cxx11::basic_string<char> >&)’     
the_entries.push_back( row_as_vector );

Relevant function:

int main(int argc, char** threshold_and_distanceMatrixfilename)
{
    if (argc < 2 || argc > 2) 
    {
        std::cerr << "Usage: ./distanceMatrixToSageGraph.o <threshold> 

            <distanceMatrix_file_calculated_fromDGEsingleCell_data>" << std::endl;
            return -1;
    }
    string distanceMatrixfilename = threshold_and_distanceMatrixfilename[2];
    int threshold = std::stoi(threshold_and_distanceMatrixfilename[1]);
    std::ifstream distanceMatrixFile(distanceMatrixfilename);

    if (!distanceMatrixFile)
    {
        std::cerr << "Error opening distanceMatrix file: " << distanceMatrixfilename << std::endl;
        return -1;
    }
    string row;
    std::getline(distanceMatrixFile, row); // discard the first row, which specifies the format of the file.
    vector<vector<int>> the_entries;

    while (std::getline(distanceMatrixFile, row))
    {
        std::stringstream row_as_stringstream(row);
        int i; i = 0;
        vector<string> row_as_vector;

        while (row_as_stringstream.good())
        {
            string substr;
            getline(row_as_stringstream, substr, ',');
            row_as_vector.push_back(substr);
        };
        the_entries.push_back(row_as_vector); //LINE 104
    };
}

Ideas:

  • It would be great if someone could explain to me: std::vector<std::vector<int>>::push_back(std::vector<std::__cxx11::basic_string<char>>&)
  • I understand that std::vector<std::vector<int>> is a matrix and that push_back adds an element at the end of the vector.
  • I suspect that we're trying to read in the wrong type in the_entries.push-back(row_as_vector).
  • The original code took a csv file as input, containing integers and strings. Now we're reading in a txt file having the shape:

    TEXT 0; INT; INT; INT; INT; ... 0; INT; INT; INT; INT; ... 18 more lines of the above numbers and semicolons

    In the above, we remove the first row in line 89.

  • Is it possible the code has to be changed much more to be able to read this txt file instead of the csv file?

Rest of error message:

In file included from /usr/include/c++/6/vector:64:0,
                 from distanceMatrixToSageGraph.c:13:
/usr/include/c++/6/bits/stl_vector.h:914:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::vector<int>; _Alloc = std::allocator<std::vector<int> >; std::vector<_Tp, _Alloc>::value_type = std::vector<int>]
       push_back(const value_type& __x)
       ^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:914:7: note:   no known conversion for argument 1 from ‘std::vector<std::__cxx11::basic_string<char> >’ to ‘const value_type& {aka const std::vector<int>&}’
/usr/include/c++/6/bits/stl_vector.h:932:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = std::vector<int>; _Alloc = std::allocator<std::vector<int> >; std::vector<_Tp, _Alloc>::value_type = std::vector<int>]
       push_back(value_type&& __x)
       ^~~~~~~~~
/usr/include/c++/6/bits/stl_vector.h:932:7: note:   no known conversion for argument 1 from ‘std::vector<std::__cxx11::basic_string<char> >’ to ‘std::vector<std::vector<int> >::value_type&& {aka std::vector<int>&&}’

Whole code:

// Convert distanceMatrix tables of protein interactions to SAGE graph.
///////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <fstream>
#include <sstream>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <list>
#include <vector>
#include <tuple>
#include <algorithm>
using namespace std;

void writeGraphInSageFormat(string name, std::vector<std::vector<int>> TheEdges) 
{
    //////////////////////////////////////////////////////////////////////////////////////
    // Write out the edges in SAGE format.
    ///////////////////////////////////////////////////////////////////////////////////////
    int edgeNumber = TheEdges.size();
    ofstream d1sageFile(name, ios::out);
    d1sageFile << "g = Graph([" << endl;

    for (int n = 0; n < edgeNumber; n++) {
        d1sageFile << "(" << TheEdges[n][0] + 1 << "," << TheEdges[n][1] + 1 << ")," << endl;
    }
    d1sageFile << "])" << endl;
    d1sageFile << "g.show()" << endl;
    d1sageFile.close();
    std::cout << "SAGE graph written into the file " << name << std::endl;
}

std::vector<std::vector<int>> ConvertEntriesMatrixToEdges(vector<vector<int>> the_entries, int threshold) 
{
    ////////////////////////////////////////////////////////////////////////////////////////////
    // Construct the edge-vertex incidence matrix (d_1) from the distanceMatrix entries matrix:
    ////////////////////////////////////////////////////////////////////////////////////////////
    std::vector<std::string> proteinNames;
    std::vector<std::vector<int>> TheEdges;
    std::cout << "Registering only edges shorter than " << threshold << "." << std::endl;
    int thisDistance;
    for (int i = 0; i < the_entries.size(); i++)
    {
        for (int j = i + 1; j < the_entries.size(); j++)
        {
            // we could use the_entries.size() instead of the_entries.at(i).size(), because this is a square matrix.
            thisDistance = the_entries.at(i).at(j);
            if (thisDistance < threshold) 
            {
                std::vector<int> CurrentEdge(2);
                CurrentEdge[0] = i;
                CurrentEdge[1] = j;
                TheEdges.push_back(CurrentEdge);
            };
        };
    };
    return TheEdges;
}

///////////////////////////////////////////
// Main Program: Extract edges from a distanceMatrix file.
///////////////////////////////////////////
int main(int argc, char** threshold_and_distanceMatrixfilename)
{
    if (argc < 2 || argc > 2)
    {
        std::cerr << "Usage: ./distanceMatrixToSageGraph.o <threshold> <distanceMatrix_file_calculated_fromDGEsingleCell_data>" << std::endl;
        return -1;
    }
    string distanceMatrixfilename = threshold_and_distanceMatrixfilename[2];
    int threshold = std::stoi(threshold_and_distanceMatrixfilename[1]);
    std::ifstream distanceMatrixFile(distanceMatrixfilename);
    if (!distanceMatrixFile) {
        std::cerr << "Error opening distanceMatrix file: " << distanceMatrixfilename << std::endl;
        return -1;
    }
    string row;  //LINE 88
    std::getline(distanceMatrixFile, row); // discard the first row, which specifies the format of the file.
    vector<vector<int>> the_entries;

    while (std::getline(distanceMatrixFile, row))
    {
        std::stringstream row_as_stringstream(row);
        int i; i = 0;
        vector<string> row_as_vector;
        while (row_as_stringstream.good())
        {
            string substr;
            getline(row_as_stringstream, substr, ',');
            row_as_vector.push_back(substr);
        };
        the_entries.push_back(row_as_vector); //LINE 104
    };
    ////////////////////////////////////////////////////////////
    // Now we assemble the entries to an edges matrix, and write it into a Sage file:
    ////////////////////////////////////////////////////////////
    std::vector<std::vector<int>> TheEdges = ConvertEntriesMatrixToEdges(the_entries, threshold);    
    char outputFilename[60]; strcpy(outputFilename, distanceMatrixfilename.c_str()); strcat(outputFilename, "AtThreshold"); string thrshld = std::to_string(threshold); strcat(outputFilename, thrshld.c_str()); strcat(outputFilename, ".txt");
    writeGraphInSageFormat(outputFilename, TheEdges);
    return 0;
}
JeJo
  • 30,635
  • 6
  • 49
  • 88
rlamesch
  • 41
  • 1
  • 8
  • 2
    `the_entries` is a `vector>` and you're trying to `push_back` `vector`. That's a vector of `string`, not `int`. That's exactly like the error message says, perhaps it confused you that it called `std::string` `std::__cxx11::basic_string`. – Blaze Jul 24 '19 at 08:31
  • you're trying to put `row_as_vector` (which is a vector of strings) into `the_entries` which is a vector of vector of integers. Hence your error. – rashmatash Jul 24 '19 at 08:32
  • @Blaze Exactly, I didn't know that `std::__cxx11::basic_string` was just `std::string` – rlamesch Jul 24 '19 at 08:56

1 Answers1

4

I suspect that we're trying to read in the wrong type in the_entries.push-back(row_as_vector)

error: no matching function for call to 
‘std::vector<std::vector<int>>::push_back(std::vector<std::__cxx11::basic_string<char> >&)’     
the_entries.push_back( row_as_vector );

Yes, your right about this. The error message says that you are trying to push back a vector of strings to a vector of vector of integers. They are entirely different types and hence not possible.

You probably want to either change the type of the_entries to

std::vector<std::vector<std::string>> the_entries;
//                      ^^^^^^^^^^^^

or

convert the strings to integers using std::stoi while pushing back to the std::vector<int> row_as_vector.

std::vector<int> row_as_vector;
while(row_as_stringstream.good())
{
        // ......
        row_as_vector.push_back(std::stoi(substr));
        //                     ^^^^^^^^^^^^^^^^^^^
};
the_entries.push_back( row_as_vector );

Is it possible the code has to be changed much more to be able to read this txt file instead of the csv file?

If the contents of those two are same, you don't need to make much difference in your code. However, ; should be parsed out before calling std::stoi to them. Because it may through invalid_argument exception for the bad argument.


A few suggestions:

  • Consider not to practice with using namespace std;. See this post for more: Why is "using namespace std;" considered bad practice?
  • When you pass the non-primitive types(i.e. std::string, std::vector.. etc) to the function, consider the case, if the parameters are read-only or not. If the data should be modified pass-by-ref and if read-only(no modification should have been made inside the function) pass them by const-ref. Read more: How to pass objects to functions in C++?
JeJo
  • 30,635
  • 6
  • 49
  • 88
  • Thank you very much. However, beforehand we used everything except the first row from the `csv` file. Now I assume we're only interested in the `integers` from the `txt` file and not the semicolons. Don't we need to remove those first, or tell the code to ignore those? – rlamesch Jul 24 '19 at 08:54
  • 1
    @rlamesch Yes, you need to [parse the semicolens](https://stackoverflow.com/questions/1894886/parsing-a-comma-delimited-stdstring/1895584) before converting them it to `int`. – JeJo Jul 24 '19 at 08:59
  • The code compiles fine now, but there remain some problems. Firstly, it seems to have an issue with **`if (argc < 2 || argc > 2) `**. It throws the "*Usage: ./a.o <> <>*" error message. However, both are strict inequalities, so the code should be fine with 2 arguments. In the original code it read **`if (argc < 2 || argc > 3) `**, which I changed it back to. – rlamesch Jul 25 '19 at 08:00
  • 1
    *" there remain some problems."*: looks like you have different problems now(other than asked above). Therefore, I would suggest asking for a new question regarding your new(other) problems. – JeJo Jul 25 '19 at 08:36