Search code examples
c++ifstream

Why can I not pass an ifstream as I construct it?


The compiler does not like the the main program below

int get1(ifstream &f){
  int count;
  f >> count;
return count;
}

int main(int argc, char** argv){
  cout << get1(ifstream(argv[1])) << endl;
}

The error message is:

test.cpp: In function 'int main(int, char**)':
test.cpp:11:33: error: invalid initialization of non-const reference of type 's\
td::ifstream& {aka std::basic_ifstream<char>&}' from an rvalue of type 'std::if\
stream {aka std::basic_ifstream<char>}'
test.cpp:4:5: error: in passing argument 1 of 'int get1(std::ifstream&)'

This does work if the main program is written as

int main(int argc, char** argv){
  ifstream f(argv[1]);
  cout << get1(f) << endl;
}

Is there a way to make the compact first form work?


Solution

  • get1(ifstream(argv[1]))
    

    You are constructing a temporary ifstream object. Temporary objects can only be bound to const references (const ifstream&), not to non-const references (ifstream&).

    Is there a way to make the compact first form work?

    It depends on which version of C++ you're using.

    In C++11 you can change your function to use a rvalue reference instead of a lvalue reference: int get1(ifstream&& f). Then it will gladly accept temporary objects. (solution courtesy of @soon)

    Note however that with this solution, if you want to use the less compact form ifstream f(argv[1]); get1(f); the compiler won't accept it as is (cannot bind ‘T’ lvalue to ‘T&&’). You'll have to use std::move in order to convert the lvalue to a rvalue: get1(std::move(f));.

    Another way, which avoids the std::move requirement, would be to use a template function with an universal reference (special case of rvalue references for templates, that allows the rvalue reference to decay to a lvalue reference): template<Stream> int get1(Stream&& f) (courtesy @soon once again)

    In C++03 there is no standard way to do it: since temporary objects can only be bound to const references, you'd have to change your function to int get1(const ifstream& f) which would render your ifstream useless (who'd want an ifstream that can't be read because it is const?).