I am writing a program for an assignment, i have a main that calls a test and the test simply tests all the functions within a class called int11, the int11 class and implementation are as follows

#ifndef INT11_H
#define INT11_H


#include "proj1.h"

class Int11 {
 private:
  T _left;                         // left endpoint
  T _right;                        // right endpoint. left <= right

  void setBoth(T left, T right);   // ensure that left <= right

 public:
  // c-tors
  Int11(T left, T right);
  Int11(T val);
  Int11();

  // output
  string toString () const;   // ww standard name. use one of below, preferably toString0
  string toString0() const;   // standard interval notation: [a, b].
  string toString1() const;   // center/radius notation: c + rW.

  // big three not needed

  // methods:
  // getters
  T getLeft() const;
  T getRight() const;
  T getCenter() const;
  T getRadius() const;
 
  // no setters

  // operators
  // equality
  bool operator != (const Int11 & rhs) const;
  bool operator == (const Int11 & rhs) const;

 
 private:
  static const string _author;
  static const string _affiliation;
  static const string _course;
  static const string _term;
  static const string _project;

 public:
  static string getAuthor();
  static string getAffiliation();
  static string getCourse();
  static string getTerm();
  static string getProject();

};

ostream & operator << (ostream & os, const Int11 & rhs);       // use toString



#endif  // Int11_H
#include "int11.h"
#include <sstream>

//const string _author ("My Name");
//const string _affiliation ("Ohio University");
//const string _course ("CS240B");
//const string _term ("Fall 2011");
//const string _Project ("Assignment 1");

Int11::Int11(T left, T right){
        if(left > right){
                _left = (left + right)/2;
                _right = (left + right)/2;
        }
        else{
                _left = left;
                _right = right;
        }
}

Int11::Int11(T val){
        _left = val;
        _right = val;
}

Int11::Int11(){
        _left = 0.0;
        _right = 0.0;
}

void Int11::setBoth(T left, T right){
 if(left <= right){
                _left = left;
                _right = right;
        }
        else{
                _left = _right = (left + right) / 2;
        }
}

T Int11::getLeft(){
        return (_left);
}

T Int11::getRight(){
        return (_right);
}

T Int11::getCenter(){
        return ((_left + _right)/2);
}

T Int11::getRadius(){
        return (((_left + _right)/2) - _left);
}

bool Int11::operator != (const Int11 & rhs) const{
        if(*this.__left != rhs._left && *this.__right != rhs._right){
                return true;
        }
}

bool Int11::operator != (const Int11 & rhs) const{
        return !(*this != rhs);
}

string Int11::toString() const{
        return toString0();
}

string Int11::toString1() const{
        ostringstream ss;
        ss << getCenter();
        ss << " + ";
        ss << getRadius();
        ss << "W";
        return (ss.str());
}

string Int11::toString0() const{
        ostringstream ss;
        ss << "[";
        ss << getLeft();
        ss << " , ";
        ss << getRight();
        ss << "]";
        return (ss.str());
}

string Int11::getAuthor(){
        return (_author);
}

string Int11::getAffiliation(){
        return (_affiliation);
}

string Int11::getCourse(){
        return (_course);
}

string Int11::getTerm(){
        return(_term);
}

string Int11::getProject(){
        return(_project);
}

ostream & operator << (ostream & os, const Int11 & rhs){
        os << rhs.getString();


const string _author ("My Name");
const string _affiliation ("Ohio University");
const string _course ("CS240B");
const string _term ("Fall 2011");
const string _Project ("Assignment 1");

my problem is in the first constructor, it gives me the error that i showed above in the title. Also in one of the files included there is a typedef double T, so thats where the T comes from.

Thanks for any help

Edited 5 Years Ago by wnr78ta: n/a

I can't really see the error, but you said that there is code that does typedef double T; . I don't think you grasp the ramifications of doing this! This is horrible, and very dangerous. The "T" is very very often used as a name for a template parameter. If you don't know what a template is, don't worry, just trust me when I say that they play a significant role in most C++ standard libraries. So, considering those two things (T being the most usual name for a template argument and the C++ standard libraries making significant use of templates), that makes the statement typedef double T; very dangerous and very likely to break any standard library that you include (like "sstream" in your case). I would not be surprised at all if that was (somehow) the source of your error.

Edited 5 Years Ago by mike_2000_17: n/a

I can't really see the error, but you said that there is code that does typedef double T; . I don't think you grasp the ramifications of doing this! This is horrible, and very dangerous. The "T" is very very often used as a name for a template parameter. If you don't know what a template is, don't worry, just trust me when I say that they play a significant role in most C++ standard libraries. So, considering those two things (T being the most usual name for a template argument and the C++ standard libraries making significant use of templates), that makes the statement typedef double T; very dangerous and very likely to break any standard library that you include (like "sstream" in your case). I would not be surprised at all if that was (somehow) the source of your error.

Alright, that might be the problem but that was code my prof wrote. He gave us all the files except our implementation and the typedef double T was in his code and he told us to use it. so if thats the problem then ill talk to him tomorrow in class.

Thanks for the help

>>the typedef double T was in his code and he told us to use it.

That does not bode well. I seriously doubt his ability to teach C++ if he makes such beginner's mistakes.

I also don't see any "std::" qualifications, can I also assume that he told you to use a header that includes a using namespace std; statement! Sh't is piling up.

The reason why most experienced programmers never do things like using namespace std; or crazy typedefs like typedef double T; , is because, although it might work sometimes, it has a bad habit of generating weird errors in code that looks perfectly fine. That's really annoying and experienced programmers develop a certain discipline to avoid setting themselves up towards those problems. If your prof ignores those very basic rules, it's a big indication he has little to no experience in C++.

A quick way to check if the typedef is the problem, is to simply swap the include statements, as so:

#include <sstream>
#include "int11.h"

The above will ensure that the standard libraries are included before any dangerous code your prof gave you is encountered.

>>the typedef double T was in his code and he told us to use it.

That does not bode well. I seriously doubt his ability to teach C++ if he makes such beginner's mistakes.

I also don't see any "std::" qualifications, can I also assume that he told you to use a header that includes a using namespace std; statement! Sh't is piling up.

The reason why most experienced programmers never do things like using namespace std; or crazy typedefs like typedef double T; , is because, although it might work sometimes, it has a bad habit of generating weird errors in code that looks perfectly fine. That's really annoying and experienced programmers develop a certain discipline to avoid setting themselves up towards those problems. If your prof ignores those very basic rules, it's a big indication he has little to no experience in C++.

A quick way to check if the typedef is the problem, is to simply swap the include statements, as so:

#include <sstream>
#include "int11.h"

The above will ensure that the standard libraries are included before any dangerous code your prof gave you is encountered.

yea im not sure what my profs experience is but he did give us a header that has the includes and typedefs, also when i switched the includes like you said i got a bunch of errors saying all my functions do not match any function in the int11 class

Well, you did forget the const qualifiers on four of your getXXXX functions, they should be:

T Int11::getLeft() const { //notice 'const' here.
        return (_left);
}

T Int11::getRight() const { //notice 'const' here.
        return (_right);
}

T Int11::getCenter() const { //notice 'const' here.
        return ((_left + _right)/2);
}

T Int11::getRadius() const { //notice 'const' here.
        return (((_left + _right)/2) - _left);
}

And your static data members require the class qualification:

//notice all the 'Int11::' here:
const string Int11::_author ("My Name");
const string Int11::_affiliation ("Ohio University");
const string Int11::_course ("CS240B");
const string Int11::_term ("Fall 2011");
const string Int11::_Project ("Assignment 1");

And, your operator << is missing the closing curly brace:

ostream & operator << (ostream & os, const Int11 & rhs){
        os << rhs.getString();
}; //notice '};' here.

Edited 5 Years Ago by mike_2000_17: n/a

Alright, i made all the changes you suggested and now I have the following errors.


int11.cc: In member function 'bool Int11::operator!=(const Int11&) const':
int11.cc:67:11: error: request for member '_left' in 'this', which is of non-class type 'const Int11* const'
int11.cc:67:39: error: request for member '_right' in 'this', which is of non-class type 'const Int11* const'

I wasnt sure how to write that function anyways, any ideas how i could make this work?

Thanks again for all your help.

also i noticed i had the != defined twice, i changed the 2nd to a ==.

Yeah the statement *this.__left (and with _right) is not correct, but it was a good try. Your intent was to dereference "this" using the *this and then access the member with the dot syntax. The problem is, the dot operation takes priority over the dereferencing (star). So, it can be solved with parentheses: (*this)._left . However, as a nicer version, C++ provides an operator that does this "dereference + dot" to access a data member of an object from a pointer, and it gives this: this->_left (using an arrow operator). That should solve your problem,

Edited 5 Years Ago by mike_2000_17: n/a

ah thats right, i remember learning something about the -> operator. Thanks for the help it compiles now but i have a core dump! going t talk to my prof about it in a few when class starts.

There's nothing wrong with typedef double T. What is wrong with it? Does it HAVE to be a template argument? No! I am siding with the professor on this one. If you are typedef'ing inside a class scope, then doing typedef double T is perfectly fine - it enables you to change the whole class to use 'double' (or some other type) by making a change in one place.

Even if you made a global declaration of typedef double T, it would be FINE! If you made a template<typename T> then the typedef would go out of scope, and there would be no problem. Would it be a best practice? No. But it wouldn't be so utterly wrong and stupid as you implied.

Mike, I don't see why you see fit to disrespect this student's teacher.

>>Does it HAVE to be a template argument? No!

Do #defines and MACROs have to be in all upper-case? No.
Does every loop index have to be called i ? No.
Does T always have to denote a template argument? No.
Does every name have to not start with an underscore? Uh.. well yes!

In programming, there are conventions (weak and strong), there are idioms and there are rules. Using all upper-case for MACROs is a strong convention, that is, it is so wide-spread that you can't reasonably break it by either having identifiers (that are not MACROs) in all upper-case or by define a macro in lower-case. Using (i,j,k..) for loop indices or using T for template arguments is idiomatic C++, something programmers learn to recognize and it becomes an expectation, e.g., when you see (i,j,k..) you expect it to be an index or when you see T you expect it to be a value-type for a simple template. Breaking this expectation is not a "crime" against the language, but it's somewhat "immoral" nonetheless (w.r.t. to the programmers). Restraining yourself from using leading underscores for identifiers is a rule of the C++ standard, and breaking it is indeed a crime against the language (you will not get a conviction but that's no reason to do it).

My point with this is that respecting the rules of C++ is necessary but not sufficient for good quality software. Respecting conventions and idioms are important to ensure portability, maintainability, code clarity, etc. etc. Pointing out what is strictly correct and what is not strictly incorrect as you did, is inconsequential.


>>I am siding with the professor on this one. If you are typedef'ing inside a class scope, then doing typedef double T is perfectly fine

Doing this typedef inside a class scope is not too terrible. It does break the idiomatic use of T and it does not provide a very descriptive name, and is thus, at least, a double offense to good coding practices. So, "perfectly fine" is not the adjective I would use, I would say "not good, but with limited negative impact".


>>it enables you to change the whole class to use 'double' (or some other type) by making a change in one place.

That's one of the simplest reasons why you would write a class template and not a normal class. Second, you don't need to call it T to be able to do that. When I code, I almost always write a series of typedefs inside a class for just about every type related to that class, but I don't call them T, I call them "value_type", "size_type", "container_type", "const_iterator_type", etc.


>>Even if you made a global declaration of typedef double T, it would be FINE! If you made a template<typename T> then the typedef would go out of scope, and there would be no problem.

Well, the typedef would not go out-of-scope, it would be hidden by the template argument. You're right that a global typedef T would not interfere with the code inside a class/function template. I just went with my gut feeling on that one, and realized later that it wouldn't really be as dangerous as I implied. I'm sorry. Of course, a global typedef with a very common name is still a very bad idea, and is not something that should be encouraged by anyone anywhere, let alone a teacher.


>>Mike, I don't see why you see fit to disrespect this student's teacher.

Well, if you read the other posts on this thread, you'll realize that the source of the error was indeed to header file provided by the prof. The teacher promotes bad coding practices, tries to avoid teaching his students about knowing the standard headers and which to include for what by providing them with an "all inclusive header" (a common practice that I despise), and provides a header that causes weird errors and related frustrations to his student because it's poorly programmed. Those three things hinder some of the most important things to learn in C++, e.g., good coding practices, learning to know the C++ standard libraries well, and learning to read and understand the errors and warnings your compiler gives you (i.e. to see the compiler as your best friend, not an enemy, which can often be a discouragement factor for beginners). The prof is either a bad teacher or a bad programmer, either way, he earned his critique. But I have no reason to "disrespect" the teacher and I'm not, I'm just questioning his competence at teaching C++, that's different.

Does every name have to not start with an underscore? Uh.. well yes!

No, but it's a good guideline if you haven't memorized the rules for when and when not to use leading underscores.

It does break the idiomatic use of T and it does not provide a very descriptive name, and is thus, at least, a double offense to good coding practices. So, "perfectly fine" is not the adjective I would use, I would say "not good, but with limited negative impact".

When writing a template class, I nearly always start out with a non-template class and typedef the "template parameters" to something like int . Then after the class is working sufficiently well, I'll remove the typedefs and make the class a true template. This has proven to be an invaluable practice for me as I'm not as rigorous as I should be with TDD. ;)

While I can't claim to know what the teacher was thinking, it's possible that this use of typedef double T; is intended as part of a series of projects on the same class which will ultimately result in a template.

@Narue: >> When writing a template class, I nearly always start out with a non-template class and typedef the "template parameters" to something like int . Then after the class is working sufficiently well, I'll remove the typedefs and make the class a true template. This has proven to be an invaluable practice for me as I'm not as rigorous as I should be with TDD.

Interesting... first time I hear that, but...
The only difference I can see between that and a class template is the fact that all the code will be compiled for a non-template class (with the "int" typedef instead of the template argument), as opposed to a class template which would just compile what is used (e.g. with TDD). For that purpose, an explicit class template instantiation works equally well (e.g. making sure all the template code compiles). Also, with your method, once you turn your class into a template, don't you have to go through a bunch of code to add the "typename" keyword (for dependent types)? That seems like more trouble then just defining it as a class template in the first place, and then instantiating it fully for a few representative types (like "int", "double" and "complex<double>" if it is intended to be an arithmetic type, and so on) as a simple test of "does everything compile for different types".

I agree that it is hard to be rigorous with TDD when writing templates, just because of the combinatorial explosion (e.g. one class template with one argument can technically be instantiated with infinitely many different types, and when you add more arguments it gets worse). I find that testing all the functionality (unit-tests) with one representative set of template parameters is usually good enough, and if there are doubts about other types, then a simple explicit instantiation for those types at least ensures that compilation works. Of course, this works for simple scenarios, like the ones for which your method applies.

either way, thanks for the help i have it working so far...next project adds a few more operators to this project then i think we start a completely new one, so not sure if this will end up a template class or not...but i do know that this project was a pain, had to do everything a kind of weird way cuz after all my code was perfect it gave me a bus error of which my prof couldnt figure out the cause. so he wrote me a makefile and for some reason that fixed it...id rather write it all myself than follow his code again but gotta do what he wants lol...

anyway thanks for the help i appreciate it!

This article has been dead for over six months. Start a new discussion instead.