1
votes

I'm working on a program that is supposed to parse a command-line input, read an input text file, and then execute the sequence of steps specified from the test file.

After working on the tokenizer class for some time, I've hit a wall, namely an error, that I'm not really sure how to solve.

So, I have Tokenizer.h:

#ifndef _TOKENIZER_GUARD
#define _TOKENIZER_GUARD 1
#include <string>
#include <cstdlib>
#include <climits>
#include <cfloat>
#include <iostream>
#include <fstream>

#include "Token.h"

//
// A class to create a sequence of tokens from an input file stream.
//
class Tokenizer
{
    public:
        Tokenizer(const std::string&, std::ostream&);
        Tokenizer(Tokenizer&); // Copy Constructor -I
        virtual ~Tokenizer();

        virtual int nextInt();
        virtual bool hasNextInt() const;
        virtual long nextLongInt();
        virtual bool hasNextLongInt() const;
        virtual float nextFloat();
        virtual bool hasNextFloat() const;
        virtual std::string next();
        virtual bool hasNext() const;
        Tokenizer& operator= (Tokenizer&); // overloaded equals operator

    protected:

    private:
        Tokenizer();
        std::ifstream stream;
        std::ostream _os;
        Token _token;
};

#endif

And Tokenizer.cpp:

#include <string>
#include <cstdlib>
#include <climits>
#include <cfloat>
#include <iostream>
#include <fstream>

#include "Tokenizer.h"

Tokenizer::Tokenizer()
{    //error occurs here

}
// Constructor 
Tokenizer::Tokenizer(const std::string& s, std::ostream& o)
{   //error occurs here
    stream.open(s);
    std::string t;
    getline(stream, t, ' ');
    _token = Token(t);
}


// Copy Constructor 
Tokenizer::Tokenizer(Tokenizer& t) :_token(t._token), stream(t.stream), _os(t._os)
{

}


// Destructor
Tokenizer::~Tokenizer()
{
     stream.close();
}

// Saves current int to return, then moves _token to the next value 
int Tokenizer::nextInt()
{
    int temp = _token.toInteger();
    std::string t;
    getline(stream, t, ' ');
    _token = Token(t);
    return temp;
}

// Checks to see if there is a next value and if it is an int
bool Tokenizer::hasNextInt() const
{
    return _token.isInteger() && hasNext();
}

// same as nextInt but long -I
long Tokenizer::nextLongInt()
{
    long temp = _token.toLongInteger();
    std::string t;
    getline(stream, t, ' ');
    _token = Token(t);
    return temp;
}

// same as hasNextInt but Long 
bool Tokenizer::hasNextLongInt() const
{
    return _token.isLongInteger() && hasNext();
}

// same as nextInt but Float 
float Tokenizer::nextFloat()
{
    float temp = _token.toFloat();
    std::string t;
    getline(stream, t, ' ');
    _token = Token(t);
    return temp;
}

// same as hasNextInt but float 
bool Tokenizer::hasNextFloat() const
{
    return _token.isFloat() && hasNext();
}

//Returns the next token 
std::string Tokenizer::next()
{
    std::string temp = _token.get();
    std::string t;
    getline(stream, t, ' ');
    _token = Token(t);
    return temp;
}

//True when it is not the end of the file
bool Tokenizer::hasNext() const
{
    return stream.eofbit != 1;
}

//Overloaded = operator 
Tokenizer& Tokenizer::operator= (Tokenizer& t)
{
    _token = t._token;
    stream = t.stream;
    _os = t._os; //error occurs here
}

I get the error

'std::basic_ostream>': no appropriate default >constructor available

for the constructor. Later, when I use 'stream = t.stream' and '_os = t._os' I get the error

function "std::basic_ostream<_Elem, _Traits>::operator=(const >std::basic_ostream<_Elem, _Traits>::_Myt &) [with _Elem=char, >_Traits=std::char_traits]" (declared at line 85 of >"x:\Visual\VC\include\ostream") cannot be referenced -- it is a deleted >function

I've been trying to find some sort of solution for the first error, but I don't understand what's causing it. Creating a copy constructor was suggested to me, but it doesn't seem to have fixed the issue. I've also included Token.h below.

#ifndef _TOKEN_GUARD
#define _TOKEN_GUARD 1

#include <string>
#include <cstdlib>
#include <climits>
#include <cfloat>

//
// Token class
//
class Token
{
public:
    Token(const std::string& t) : _token(t) { }

    virtual std::string get() const { return _token; }

    virtual long toLongInteger() const;
    virtual bool isLongInteger() const;
    virtual int toInteger() const;  // for int and is int functions
    virtual bool isInteger() const; //
    virtual float toFloat() const;
    virtual bool isFloat() const;
    virtual bool isNonNumeric() const;
    Token() : _token("") {}
    std::string _token;
protected:

};

#endif

I apologize in advance if I'm being too vague or something along those lines. I'm more than happy to provide anything else needed (since I'm stuck at the moment).

1

1 Answers

2
votes

The compiler error message is very clear. When you use:

Tokenizer::Tokenizer(const std::string& s, std::ostream& o)
{   //error occurs here
    stream.open(s);
    std::string t;
    getline(stream, t, ' ');
    _token = Token(t);
}

the member variable os_ is default constructed. Since there is no default constructor in std::ostream, os_ cannot be initialized.

I am guessing that you mean to initialize the member variable os_ with the input argument to the constructor of Tokenizer, like:

Tokenizer::Tokenizer(const std::string& s, std::ostream& o) : os_(o) 
{
   ...

Even that won't work since std::ostream does not have a copy constructor. You'll need to change the member variable to a reference object.

std::ostream& os_;

Then, you can safely use:

Tokenizer::Tokenizer(const std::string& s, std::ostream& o) : os_(o) 
{
   ...

You just have to make sure that the input argument, o, is not destroyed before the Tokenizer is destroyed. Otherwise, the Tokenizer object will be left with a dangling reference.