so I've got a project where I am inserting user entered data into classes. So I've overloaded the >> operator. Because I have classes with similar structures, I made the overload a template to try to save time. Making this template overload a friend of the classes seems to work, as I get no compile errors.
My ClassDefs.h:
// ClassDefs.h
using namespace std;
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <tuple>
#include <map>
#include <typeinfo>
class measurement {
//friends
template<class measT> //measT are other similar measurement classes
friend istream & operator >> (istream&, measT&);
private:
string words;
public:
//constructors and things like that here
};
template<class measT>
istream& operator >> (istream& is, measT& meas) {
//a series of checks to ensure user entry is valid
//enter user entry into private data
//e.g.
string line;
getline(is,line);
meas.words = line;
return is;
}
The problem comes when using cin >> foo in main - I get a warning caption saying "more than one operator >> matches these operands". Accompanied by:
error C2593: 'operator >>' is ambiguous
This makes sense, but my crude understanding of overloads was that they allow you to use different types with that operator and the compiler "understands" which definition to use for each situation.
My main.cpp:
// main.cpp
#include "ClassDefs.h"
int main(){
string entry;
cin >> entry;
^^ error here
return 0;
}
I have looked around and seen things involving explicit, inline, namespace (my using namespace std; seems dodgy) but I haven't seen anyone use this template overload arrangement and have this problem. I'm using Visual Studio 2015 Community.
Any help or advice would be greatly appreciated :)
So I solved this partially with the help of #user4581301 - I really needed to keep the >> overload a template so that I could use that parameter for a template exception class inside it.
It has become a bit convoluted but I thought I'd share in case anyone else is having issues overloading operators with templates.
Firstly I changed measurement from an abstract base class to a base class (so that it could be used as a template parameter) and changed the friend declaration inside to:
//ClassDefs.h
template <class measT>
friend istream& operator >> (istream&, measurement&);
Where measT was the type of measurement involved, to be used as the parameter for the exception class.
Then later on in the header file, >> was overloaded with the definition:
//ClassDefs.h
template<class measT>
istream& operator >> (istream& is, measurement& meas) {
//take user input
//do checks on it, throw Exception<measT> depending on which set of
exceptions are relevant
}
And most importantly I wasn't sure how to use an operator with a template parameter but it turns out you can do it explicitly:
//ClassDefs.h
template<class measT>
measT userNewMeas() { //function to take user input and make into a type
// of measurement
try { ::operator>><measT> (cin,newMeas); }
catch (Exception<measT>& error) {
cout << error << endl; // this output depends on which exception
// was called
}
And now I can use template userNewMeas() in main.cpp with template >> and template Exception. The goal is probably hard to see for everyone but I was trying to overload >> for any measurement type, and have one Exception class containing different error messages to be thrown depending on which measurement was being entered.
Related
This is my sample code:
#include <iostream>
#include <string>
using namespace std;
class MyClass
{
string figName;
public:
MyClass(const string& s)
{
figName = s;
}
const string& getName() const
{
return figName;
}
};
ostream& operator<<(ostream& ausgabe, const MyClass& f)
{
ausgabe << f.getName();
return ausgabe;
}
int main()
{
MyClass f1("Hello");
cout << f1;
return 0;
}
If I comment out #include <string> I don't get any compiler error, I guess because it's kind of included through #include <iostream>. If I "right-click --> Go to Definition" in Microsoft VS they both point to the same line in the xstring file:
typedef basic_string<char, char_traits<char>, allocator<char> >
string;
But when I run my program, I get an exception error:
0x77846B6E (ntdll.dll) in OperatorString.exe: 0xC00000FD: Stack overflow (Parameter: 0x00000001, 0x01202FC4)
Any idea why I get a runtime error when commenting out #include <string>? I'm using VS 2013 Express.
Indeed, very interesting behavior.
Any idea why I get I runtime error when commenting out #include <string>
With MS VC++ compiler the error happens because if you do not #include <string> you won't have operator<< defined for std::string.
When the compiler tries to compile ausgabe << f.getName(); it looks for an operator<< defined for std::string. Since it was not defined, the compiler looks for alternatives. There is an operator<< defined for MyClass and the compiler tries to use it, and to use it it has to convert std::string to MyClass and this is exactly what happens because MyClass has a non-explicit constructor! So, the compiler ends up creating a new instance of your MyClass and tries to stream it again to your output stream. This results in an endless recursion:
start:
operator<<(MyClass) ->
MyClass::MyClass(MyClass::getName()) ->
operator<<(MyClass) -> ... goto start;
To avoid the error you need to #include <string> to make sure that there is an operator<< defined for std::string. Also you should make your MyClass constructor explicit to avoid this kind of unexpected conversion.
Rule of wisdom: make constructors explicit if they take only one argument to avoid implicit conversion:
class MyClass
{
string figName;
public:
explicit MyClass(const string& s) // <<-- avoid implicit conversion
{
figName = s;
}
const string& getName() const
{
return figName;
}
};
It looks like operator<< for std::string gets defined only when <string> is included (with the MS compiler) and for that reason everything compiles, however you get somewhat unexpected behavior as operator<< is getting called recursively for MyClass instead of calling operator<< for std::string.
Does that mean that through #include <iostream> string is only included partly?
No, string is fully included, otherwise you wouldn't be able to use it.
The problem is that your code is doing an infinite recursion. The streaming operator for std::string (std::ostream& operator<<(std::ostream&, const std::string&)) is declared in <string> header file, although std::string itself is declared in other header file (included by both <iostream> and <string>).
When you don't include <string> the compiler tries to find a way to compile ausgabe << f.getName();.
It happens that you have defined both a streaming operator for MyClass and a constructor that admits a std::string, so the compiler uses it (through implicit construction), creating a recursive call.
If you declare explicit your constructor (explicit MyClass(const std::string& s)) then your code won't compile anymore, since there is no way to call the streaming operator with std::string, and you'll be forced to include the <string> header.
EDIT
My test environment is VS 2010, and starting at warning level 1 (/W1) it warns you about the problem:
warning C4717: 'operator<<' : recursive on all control paths, function will cause runtime stack overflow
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;
I have the InstancePool class (part of it below) with the Instance.h header included, but I get the error in the title in the operator>> function of InstancePool.
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <sstream>
#include <stdlib.h>
using namespace std;
#include "Instance.h"
#include "InstancePool.h"
istream &operator >> (istream &in , InstancePool &ip) {
ip.Instances->clear();
string input;
getline(in , input);
while (!in.eof()) {
Instance inst;
Instance::operator >>(in , inst); // <- line giving me the error
ip.Instances->push_back(inst);
getline(in , input);
}
}
The InstancePool operator>> function is a 'friend' function BTW, and so is the same function in Instance. Probably I'm trying to access the Instance 'operator>>' in the wrong way but I'll be damned if I know the correct one...
Any help?
Friend functions aren’t member functions, you cannot explicitly qualify the function’s name the way you did because it’s simply not inside a namespace called Instance.
The good news is: you don’t need to. Just call it normally:
in >> inst;
There are more bugs in your code, though. First off, while (in.eof()) will result in an infinite loop when there’s an error while reading – never do this.
Second of all, you’re reading and discarding lines with getline. This is probably not what you want to do, right? Do you want to read each instance from the line or directly from the input stream?
I'm fairly new to C++, sorry if my questions aren't quite specific enough. Here goes.
I'm trying to overload the >> operator for a class which I have called "book."
"Book" contains 'title,' 'author,' and 'publisher' string objects, a 'student count' int, and a 'price' double variable. Part of my assignment is to take these values from a provided .txt file and load values into their corresponding variables/objects. All values are on their own lines within the .txt file, and they each follow this format:
//Title, Author, Publisher, Price
Starting Out with Java
Gaddis
Scott/Jones
105.99
I try to use getline() to take the string values (I use a temp string after I take the price double), but when I type it in, Visual Studio says:
Error: no intsance of overloaded function 'getline' matches the argument list.
I don't understand this. I included both <iostream> and <string>, which I believe are both required for getline to work. I'm working on getting the class file down before moving to the main code, so I apologize for not having a main code to post. Here's the .cpp file for class book:
#include <iostream>
#include <string>
#include "book.h"
using namespace std;
book::book()
{
}
book::~book()
{
}
istream& operator>> (istream &in, book &bookInfo) {
string temp;
getline(in, bookInfo.title);
return in;
}
There's question number 1 down...
Assuming I can get getline to work, I have another problem.
Visual Studio says that bookInfo.title is inaccessible, even though this is the accompanying .cpp file to the class. I even have the istream& function listed as a friend function in the class itself:
#include <iostream>
#include <string>
class book {
friend istream& operator>> (istream&, book&);
public:
book();
virtual ~book();
private:
string title;
string author;
string publisher;
double price;
};
It should be noted that I used much the same syntax for another class, and was given no error messages.
Thanks for a very quick reply.
In your header, you're not using std::. Fix that:
class book
{
friend std::istream& operator>> (std::istream&, book&);
public:
book();
virtual ~book();
private:
std::string title;
std::string author;
std::string publisher;
double price;
};
getline is a method of std::istream class, see here:
istream& getline (char* s, streamsize n );
istream& getline (char* s, streamsize n, char delim );
You should call it on class instance e.g.
your_input_stream.getline( your_params ... )
I have this code in my header file and Ive got loads of errors on the ostream and istream lines. One error is "missing ";" before "&"" and im confuzzled, im new to this sorry
#pragma once
class ArrayIntStorage
{
public:
void readFromFile();
bool setReadSort(bool);
void sortStd();
void sortOwn();
ArrayIntStorage(void);
~ArrayIntStorage(void);
};
ostream& operator<< (ostream &out, const ArrayIntStorage &a);
istream& operator>> (istream &in, ArrayIntStorage &b);
thanks in advance
Looks like you just need to do
#include <ostream>
#include <istream>
then place a std namespace qualifier in front of them on those lines, ie:
std::ostream& operator<<(std::ostream& out,...)
It's not clear to me the context this code appears in but the error suggests that these declarations appear before ostream and istream are defined.
Are you including the proper header files in the proper order?
You omitted includes:
#include <istream>
#include <ostream>
Note: all the standard types like istream, ostream live within a namespace called std. So in order to be able to use them you need to either:
prefix them with std:: or
use the namespace (using namespace std;). This is a very bad practice for a header file as it may cause naming clashes in the header files that are included later on.
Add the iostream include and Put the method prototype inside the class and declare it friend. I can't give more details since I am replying from my mobile.
Here is a link: Operator-Overloading/Classlevelostreamoperatorandistreamoperator.htm">http://www.java2s.com/Tutorial/Cpp/0200_Operator-Overloading/Classlevelostreamoperatorandistreamoperator.htm