Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ - Invalid initialization of non-const reference of type

Tags:

c++

I'd like to start by saying that yes, I Google'd this problem before coming here, and none of the answers seemed relevant.

I stole the below code from What's the best way to trim std::string?, because for whatever reason, there is no standard c++ trim function. Using Visual Studio, it compiled fine, and I managed to complete the rest of the project without it giving me any errors.

This morning though, I decided to try compiling the entire project manually (using g++ -std=c++11 *.cpp), and now suddenly the trim functions are yielding the following error:

DVD.cpp: In static member function 'static DVD DVD::parseDVD(std::string, std::string)':
DVD.cpp:65:59: error: invalid initialization of non-const reference of type 'std::string& {aka std::basic_string<char>&}
 from an rvalue of type 'std::basic_string<char>'
 std::string rID = trim(dataStr.substr(0, preTitlePos - 1));

It yields similar errors for the other 2 times that trim is used.

Here is the "stolen" code:

(Utils.h):

static inline std::string& ltrim(std::string& s) {
    s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
    return s;
}

// trim from end
static inline std::string& rtrim(std::string& s) {
    s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
    return s;
}

// trim from both ends
static inline std::string& trim(std::string& s) {
    return ltrim(rtrim(s));
}

And here is the parseDVD function that the error mentions:

(DVD.cpp):

DVD DVD::parseDVD(std::string dataStr, std::string delimiter) {
    DVD newDVD;
    int preTitlePos = dataStr.find(delimiter, 0);
    int preGenrePos = dataStr.find(delimiter, preTitlePos + 1);

    // V Error is here V
    std::string rID = trim(dataStr.substr(0, preTitlePos - 1));
    std::string rTitle = trim(dataStr.substr(preTitlePos + 1, preGenrePos - preTitlePos - 1));
    std::string rGenre = trim(dataStr.substr(preGenrePos + 1));

    int parsedID = 0;
    //Requirements for a successful parse
    //The ID must be fully numeric, and both of the delimiters must have been found
    if (parseInt(rID, parsedID) && preTitlePos > -1 && preGenrePos > -1) {
        return
            newDVD  .setID(parsedID)
                    .setTitle(rTitle)
                    .setGenre(rGenre);
    }

    return badDVD;
}

If I remove all of the &s from the trim functions, it works, but I'd rather it not make copies constantly.

This baffles me because I know the code is sound; not only is it the accepted answer to the above question, but it works fine in Visual Studio.

like image 441
Carcigenicate Avatar asked Mar 23 '15 12:03

Carcigenicate


1 Answers

Your trim() function is expecting a non-const reference to a std::string. When you invoke it like this:

std::string rID = trim(dataStr.substr(0, preTitlePos - 1));

You are invoking it with an rvalue, an unnamed temporary. This will have type const std::string &, so it is not compatible with the trim() function. In order to make it work, you would need to assign it to a named variable first:

std::string temp = dataStr.substr(0, preTitlePos - 1);
std::string rID = trim(temp);

On a side note, you seem to be mixing two methods of returning outputs from the trim() function. Typically, one will either return the function's result (usually by value), or one will modify arguments that were passed to the function by reference. Your functions do both, which is not typical.

I would change them to either take an input argument and return the result by value, or modify the by-reference argument that you pass in (and change their return types to void).

like image 190
Jason R Avatar answered Oct 18 '22 18:10

Jason R