Why C++ allows returning ifstream object? - c++

In C++98, the following code does not compile because the ifstream has no copy constructor:
#include <iostream>
#include <fstream>
using namespace std;
ifstream f() {
return ifstream("main.cpp");
}
int main() {
ifstream st= f();
}
However using multiple GCC versions with C++11, this compiles without warnings. What is the reason of this?

C++11 added move constructors. The stream is now moved. The source object here is a temporary in the return expression, which can be moved to the st object in main.

Related

Strings as File names

If I set a string as a filename, it doesn't work and I have no idea why. (I'm using codeblocks and it seems to work on other IDEs)
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
string FileName="Test.txt";
ofstream File;
File.open(FileName);
}
This does not work,while this next one does:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ofstream File;
File.open("Test.txt");
}
Error message:
no matching function for call to std::basic_ofstream::open(std::string&)
Can someone help a bit with this problem, I cannot understand why this error occurs.
Due to what should be considered a historical accident in the early era of C++ standardisation, C++ file streams originally didn't support std::string for filename parameters, only char pointers.
That's why something like File.open(FileName), with FileName being a std::string, didn't work and had to written as File.open(FileName.c_str()).
File.open("Test.txt") always worked because of the usual array conversion rules which allow the "Test.txt" array to be treated like a pointer to its first element.
C++11 fixed the File.open(FileName) problem by adding std::string overloads.
If your compiler doesn't support C++11, then perhaps you should get a newer one. Or perhaps it does support C++11 and you just have to turn on the support with a flag like -std=c++11.

Unable to call member functions

I'm pretty sure I'm probably doing something stupid, but I've been at this an hour and a half and can't figure out what I'm missing.
I can create an object from my class using the default constructor, but can't use an overloaded constructor when I add one. I can't call the print member function that I have included or any others that I have tried to include either. I have put the three files into a Code::Blocks project and gotten the same result. I have also tried the three files on Dev-Cpp with the same result. Any help would be greatly appreciated.
Main Function
#include <iostream>
#include "Appt.h"
using namespace std;
int main()
{
Appt a();
a.print();
}
Appt.h
#ifndef APPT_H
#define APPT_H
#include <iostream>
#include <string>
using namespace std;
class Appt
{
public:
Appt();
void print();
private:
string description;
};
#endif // APPT_H
Appt.cpp
#include "Appt.h"
using namespace std;
Appt::Appt()
{
description = "No Description";
}
void Appt::print()
{
cout << description << endl;
}
I am using Code::Blocks 16.01 with the GCC compiler. These files are not currently in a project. I am also running Windows 7.
It looks like your problems may be related to this line:
Appt a();
Unfortunately, while this looks like it calls the default constructor, it actually declares a to be of type Appt(), that is, a function taking no arguments and returning Appt. If you want to call the default constructor, there are a few options:
Appt a;
Appt a = Appt();
Appt a{}; // requires C++11
I would prefer the last one.

syntax error when using ifstream

It's been a long time since I've done any C++. What's wrong with this code?
#include <iostream>
#include <fstream>
using namespace std;
main()
{
ifstream& ifs("foo.txt");
}
Gives:
$ g++ foo.cc
foo.cc: In function ‘int main()’:
foo.cc:7:25: error: invalid initialization of non-const reference of type ‘std::ifstream& {aka std::basic_ifstream<char>&}’ from an rvalue of type ‘const char*’
ifstream& ifs("foo.txt");
You used a & when you should not have done.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream ifs("foo.txt");
}
Passing values by reference isn't done in the variable declaration, but instead in the parameter list of the function using the ifstream object. For example, your function main might look like this:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream ifs("foo.txt");
myFunction(ifs);
}
and your called function should look like this:
void myFunction(std::ifstream& in_stream)
{
// ...
}
If you need the C++11 reference type (which I doubt, but maybe), try this:
ifstream ifs("foo.txt.");
std::ref<std::ifstream> ifs_ref(ifs);
That works in a lot of cases where doing a regular by-ref wouldn't.
semantically, a reference is a pointer. so your code doesn't compile for the same reason this code doesn't:
main()
{
ifstream* ifs("foo.txt");
}
as others have said, you want to create an object of type ifstream. not a reference (nor a pointer) to it.

implementing function in a class causes error: member reference base type 'ifstream (string)' is not a structure or union

I'm trying to implement a function that reads a column of data from a text file and stores it in a vector, which works. However when I try to implement it inside of a class I'm clearly missing some step. This causes the terminal to output the following message:
Outout for
error: member reference base type
'ifstream (string)' is not a structure or union
...
error: member reference base type
'ifstream (string)' is not a structure or union
while(!file.eof()){
..
error: invalid operands to binary
expression ('ifstream (*)(string)' and 'double')
file >> line;
In my class I try to implement the following function to be used with it's data members:
#include <iostream>
#include <vector>
#include <stdio.h>
#include <fstream>
using namespace std;
class spectData{
public:
vector<double> x, y, z;
vector< int> A;
vector<double> readVector(string){
ifstream file(string);
double line;
vector<double> a;
if(file.fail()){
cout << "-----------------\n";
cout << "Input file error!\n";
}
while(!file.eof()){
file >> line;
a.push_back(line);
}
return a;
};
};
Any hint as to why this wouldn't work inside a function, but would inside main function?
using namespace std;
...
vector<double> readVector(string){
// ~~~~~~^
// missing parameter name
ifstream file(string);
// ~~~~~^
// whoops, type name aka std::string instead of parameter name
What your ifstream file(string); currently does, it declares a function file that takes by value a parameter of the std::string type and returns the std::ifstream instance. Hence the error you get. What you probably meant to do is to supply a path parameter to your file's constructor:
vector<double> readVector(const string& path){
// ~~~~~~~~~~~~~~~~~^
// parameter name
ifstream file(path.c_str());
// ~~~^ ~~~~~~^
//
The issues in this code are numerous, including:
Failing to include <string>. Don't rely on another header to do that for you.
Invalid parameter naming (as in, you have none; remember parameters are Type name).
Building on the mistake from above, ifstream file(string); therefore declares a function called file that takes a string parameter and returns an ifstream (which is impossible, as that class does not support copy construction, but does support move construction, not that it matters here).
Using .eof() as a loop condition, which is nearly always wrong (and this is no exception). Read this for why.
Minor: Reinventing the iterative read operation. std::istream_iterator provides this functionality for you, and should be exploited.
Minor: blanketing this with using namespace std;
For example:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>
class spectate
{
public:
std::vector<double> x, y, z;
std::vector< int> A;
std::vector<double> readVector(const std::string& fname)
{
std::vector<double> res;
std::ifstream file(fname);
if(!file)
{
std::cout << "-----------------\n";
std::cout << "Input file error!\n";
}
else
{ // dump the file of doubles into your vector
std::copy(std::istream_iterator<double>(file),
std::istream_iterator<double>(),
std::back_inserter(res));
}
return res;
}
};
Truth be told, you can forego much of that if error reporting is handled by the caller (such as an empty file, vector, etc), at which point that entire member can be reduced to simply:
std::vector<double> readVector(const std::string& fname)
{
std::ifstream file(fname);
return std::vector<double> {
std::istream_iterator<double>(file),
std::istream_iterator<double>() };
}
It somewhat brings into question whether the function is truly even needed at all. The caller could just as easily have done this entirely on their side.
string is a typename that you've pulled in inadvertently via the using namespace std. As a result, file is not what you intended - it is a function taking a std::string and returning an std::ifstream. Avoid using namespace std except in very controlled scopes - definitely not in header files.
#include <vector>
does includes std::string. After using namespace std; std::string becomes type string so you cant use string as variable name because it is a type.
You should write using std::vector; instead of using namespace std;

Why can't initialize the static member in a class in the body or in the header file?

Could any body offer me any reason about that?
If we do it like that, what's the outcome? Compile error?
The problem is that static initialization isnt just initialization, it is also definition. Take for example:
hacks.h :
class Foo
{
public:
static std::string bar_;
};
std::string Foo::bar_ = "Hello";
std::string GimmeFoo();
main.cpp :
#include <string>
#include <sstream>
#include <iostream>
#include "hacks.h"
using std::string;
using std::ostringstream;
using std::cout;
int main()
{
string s = GimmeFoo();
return 0;
}
foo.cpp :
#include <string>
#include <sstream>
#include <iostream>
#include "hacks.h"
using std::string;
using std::ostringstream;
using std::cout;
string GimmeFoo()
{
Foo foo;
foo;
string s = foo.bar_;
return s;
}
In this case, you can't initialize Foo::bar_ in the header because it will be allocated in every file that #includes hacks.h. So there will be 2 instances of Foo.bar_ in memory - one in main.cpp, and one in foo.cpp.
The solution is to allocate & initialize in just one place:
foo.cpp :
...
std::string Foo::bar_ = "Hello";
...
It is just a limitation in the language it self. Hopefully, when C++0x becomes reality, this limitation would go away.
I think this page gives a somehow good reason:
One of the trickiest ramifications of
using a static data member in a class
is that it must be initialized, just
once, outside the class definition, in
the source file. This is due to the
fact a header file is typically seen
multiple times by the compiler. If the
compiler encountered the
initialization of a variable multiple
times it would be very difficult to
ensure that variables were properly
initialized. Hence, exactly one
initialization of a static is allowed
in the entire program.