1

I'm new to C++ and SO to I apologize in advance if everything isn't up to snuff.

Below are the first few lines of my main function. I get an error on the 6th line: 'missing template arguments before c1'. As you can see further below the class 'complex' has to double data members which should both be initialized to 0 with the default constructor. entering complex fixed this error but I don't believe I should need a template in the first place. Another issue is that after I make this change, the compiler does not recognize the first member function that I use c1.get_real() which I suspect is due to the addition of the template argument.

#include <fstream> // For ofstream class declaration
#include <iostream> // For cout, endl
#include <Complex> // So we can access the complex class declaration (hint: see Complex.cpp)
#include <string>


int main()
{
    string filename; filename = "complex-test.txt";
    ofstream fout(filename.c_str());
    fout<<"Defining complex object c1 and calling default ctor"<<endl;
    complex c1;
    fout<<"Testing accessors and that default ctor initialized c1 to 0 + 0i"<<endl;
    fout<<"c1.get_real() returned "<<c1.get_real()<<endl;

My Complex.cpp file which implements my class member functions:

#include <iomanip>      // For fixed, setprecision()
#include <sstream>      // For stringstream class
#include "Complex.hpp"  // For the complex class declaration

using namespace std;

//--------------------------------------------------------------------------------------------------
// + complex() :
// PSEUDOCODE
// Call init() passing 0 and 0 as the arguments.
//--------------------------------------------------------------------------------------------------
    complex::complex()
    {
        init(0,0);
    }


 complex::complex(double init_real, double init_imag)
 {
    init(init_real, init_imag);
 }


 double complex::get_imag()
 {
     return m_imag;
 }


double complex::get_real()
{
    return m_real;
}


void complex::init(double init_real, double init_imag)
{
    m_real = init_real;
    m_imag = init_imag;
}


void complex::set_imag(double s)
{
    m_imag = s;
}


void complex::set_real(double s)
{
    m_real = s;
}


//--------------------------------------------------------------------------------------------------
// + to_string() : string
//
// DESCRIPTION
// Returns a string representation of the complex object. For example, if m_real is -2.3333333
// and m_imag is -21.456789123, this function will return the string "(-2.3333 - 21.4568i)".
//
//--------------------------------------------------------------------------------------------------
string complex::to_string()
{
    stringstream sout;
    sout << fixed << setprecision(4);
    sout << "(" << get_real();
    double imag = get_imag();
    if (imag < 0) {
        sout << " - " << -imag << 'i';
    } else if (imag > 0) {
        sout << " + " << imag << 'i';
    }
    sout << ")";
    return sout.str();
}

Here is the header file for the class:

#ifndef COMPLEX_HPP  // See the comments in the header comment block regarding these two lines.
#define COMPLEX_HPP

#include <string> // Included because we are using the string class in to_string()
using namespace std;

class complex
// Write the public section of the class declaration.
{
    public:

    complex();

    complex(double , double);

    double get_imag();

    double get_real();

    void set_imag(double);

    void set_real(double);

    string to_string();
    private:

    void init(double, double);

    double m_real;

    double m_imag;
};

#endif
GBlodgett
  • 12,704
  • 4
  • 31
  • 45
Elmer
  • 75
  • 5
  • 5
    This is what you get when you use `using namespace std;`. There exists a standard class [std::complex](https://en.cppreference.com/w/cpp/numeric/complex), and since you added all names from `namespace std` to global namespace, the compiler is confused on which one should it choose. – Yksisarvinen Nov 17 '18 at 21:26
  • 1
    Also see [Why is “using namespace std” considered bad practice?](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice) – Yksisarvinen Nov 17 '18 at 21:27
  • @Yksisarvinen OP (hopefully) doesn't include `` though – Swordfish Nov 17 '18 at 21:27
  • 1
    @Swordfish I guess one of the system headers includes it? I don't see any other explanation, since OP's code has no templates in it. – Yksisarvinen Nov 17 '18 at 21:30
  • 1
    `using namespace std;` -- First and foremost, remove this from the `Complex.hpp` header file. – PaulMcKenzie Nov 17 '18 at 21:30
  • If what you have in your files is what you have shown here could you clean your project and recompile it? I don't see a declerations of a template in your code to begin with so..?? – johnathan Nov 17 '18 at 21:31
  • The only thing from namespace `std` used in your `complex.hpp` is `std::string`, and is easily fully namespace qualified with a few more keystrokes (less than it took to type out `using namespace std;`. Unrelated, *all* of those getters should be `const`. – WhozCraig Nov 17 '18 at 21:32
  • @Elmer it's not `string` but `std::string`. – Swordfish Nov 17 '18 at 21:35
  • @Yksisarvinen all that's implimentation defined so they are free to include the entire STL with just if they want to, in practice though it's possible that iomanip or the stream classes use , just my best guess – johnathan Nov 17 '18 at 21:35
  • @Elmer The full name of the class is `std::string`. If you add `using namespace std;` somewhere in your code, compiler will let you omit the `std::` qualifier. Now, when you have removed it, the names have to be fully qualified, using `std::` prefix for every standard class/object/function. This may seem tedious, but is actually a very good practice and makes code more readable for others (and lets you avoid some weird bugs like the one you encountered). – Yksisarvinen Nov 17 '18 at 21:38
  • @Yksisarvinen That resolved that issue, but now I'm getting a new error message saying 'complex is not declared in this scope' I added the header files I used for my main file? Did I not reference the .cpp file for my class correctly (it's named Complex.cpp and is in the same folder as the rest of the files) – Elmer Nov 17 '18 at 21:41
  • Did you `#include "Complex.hpp"` in your main? – Yksisarvinen Nov 17 '18 at 21:43
  • @Yksisarvinen No, but I did include it in my "Complex.cpp" file which I did include in the main file? Does this not work? – Elmer Nov 17 '18 at 21:47

1 Answers1

4

The problem

If you're running your compiler on a case-insensitive operating system (Windows ?), this line:

#include <Complex> // So we can access the complex class declaration (hint: see  Complex.cpp)

will cause the standard header <complex> (all lowercase) to be included and therefore the template std::complex to be load. Note that on a linux system, you would get the right error (that the header Complex with upaercase) is not found.

You then have two complex types in your code: std::complex and you complex. The fact that you have using namespace std makes complex and std::complex synonyms. This is where your error comes from.

The solution

First, if you don't need the standard complex, don't include it. So in the main unit, use the same include than in your complex.cpp:

#include "Complex.hpp"  // For YOUR complex class declaration

Second, avoid using namespace std. At least in your headers. Just prefix standard objects with std::. Or list the standard objects that you explicitly want to use without the prefix: using std::cout;.

Additional remark: some C++ styles suggest to define your own class names with a starting capital. This prevents conflicts with the std. But this approach is not a remplacement for the recommendations above, since name clashes would sill be possible with other libraries that may use the same kind of style.

Christophe
  • 68,716
  • 7
  • 72
  • 138