views:

52

answers:

2

Hi all, I have some code with a few errorr I do not understand how to fix at all. I have asked my professor and TA, and consulted the internet with no luck, apart from understanding more precisely what the errors mean. From what I can tell, the compiler is either confusing my overloaded operator with built in operators, or it is not recognizing it as an overloaded operator at all.

I am getting the following errors and warnings:

||=== project 4, Debug ===| \project 4\forest.h|13|warning: friend declaration 'Forest& operator+(Forest&, Forest&)' declares a non-template function|

\project 4\forest.h|13|note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) |

\project 4\forest.h|14|warning: friend declaration 'std::ostream& operator<<(std::ostream&, const Forest&)' declares a non-template function|

\project 4\forest.h|15|warning: friend declaration 'std::istream& operator>>(std::istream&, Forest&)' declares a non-template function|

\project 4\main.cpp||In function 'int main()':| \project 4\main.cpp|21|error: ambiguous overload for 'operator>>' in 'file >> intForest'|

c:\program files (x86)\codeblocks\mingw\bin..\lib\gcc\mingw32\4.4.1\include\c++\istream|119|note: candidates are: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_istream<_CharT, _Traits>& (*)(std::basic_istream<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits] |

c:\program files (x86)\codeblocks\mingw\bin..\lib\gcc\mingw32\4.4.1\include\c++\istream|123|note: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_ios<_CharT, _Traits>& (*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits] |

c:\program files (x86)\codeblocks\mingw\bin..\lib\gcc\mingw32\4.4.1\include\c++\istream|130|note: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::ios_base& (*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits] | ||=== Build finished: 1 errors, 3 warnings ===|

When I try to compile my code. The relevant code segments are as follows:

(in forest.h)

template< typename NODETYPE > class Forest
{

    public:
        friend Forest<NODETYPE>& operator+(Forest<NODETYPE>&, Forest<NODETYPE>&);
        friend ostream& operator<<(ostream&, const Forest<NODETYPE>&);
        friend istream& operator>>(istream&, Forest<NODETYPE>&);

        Forest();
        Forest( const Forest& otherForest);
        ~Forest();
        void nodes(int&) const;

    private:
        ForestNode<NODETYPE> *root;

        ForestNode<NODETYPE> *getNewNode( const NODETYPE &);
};

(in forest.cpp)

template<typename NODETYPE> istream& operator>>(istream& file, const Forest<NODETYPE>& f1)
{
    istream file2 = file;
    int nodeCount = 0;
    string blah = ' ';

    while(getline(file2,blah))
    {
        nodeCount++;
    }

    ForestNode<NODETYPE> *forestNodeArray[nodeCount];//holds pointers to last node of depth i

    getline(file,*f1.root.tag);
    forestNodeArray[0] = &(*f1.root);
    inputHelper(file, 0, *f1.root, forestNodeArray, nodeCount);

    return file;
}

(and finally, in main.cpp)

int main()
{

    Forest < char > intForest();
    filebuf fb;
    fb.open ("forest1.txt",ios::in);
    istream file(&fb);


    cout << typeid(intForest).name() << endl;
    cout << typeid(file).name() << endl;

    file >> intForest;

    fb.close();


}

Any help would be greatly appreciated.

EDIT: Thanks to alex and alf, I understand why they were not considered template functions. It's quite obvious in retrospect, I was just set on those signatures. Anyway, I still get the error about the ambiguous operator. Why does the compiler not recognize my operator and use it, instead of trying to decide between 3 built in versions of the operator that could not possibly have one parameter as Forest?

A: 

The (first) warning tells you that the befriended function is not a template.

And it isn't.

Think about how you would implement it. It would entail writing one such function for each possible NODE_TYPE.

There are several ways to fix that.

One way is to befriend a function template, like so:

template< class Type >
struct S
{
    template< class U > friend void foo( S<U> );
};

template< class Type >
void foo( S< Type > x ) {}

int main()
{}

Cheers & hth.,

Alf P. Steinbach
Thanks alf. You and alex definitely clarified the proper syntax to do such things, my Dietel reference does not have any examples of a generic friend function. If you could possibly clue me in as to why c++ is confusing my >> operator with ones built into istream, that would be great, but thanks for the help you've given.
joedillian
+1  A: 

The second error is in this line:

Forest < char > intForest();

This may be surprising at first, but that line is not declaring a variable of type Forest<char>, but rather a function that takes no arguments and returns a Forest<char>. Just remove the parenthesis from the declaration:

Forest < char > intForest;

On the first warning, which is already explained (the function declared as friend is not a template, and that means that you will manually have to implement it for each type you use to instantiate Forest<> with (probably you don't want that). Also note that declaring the templated operator+ and then making the template a friend as in @Alf P. Steinbach answer means that a Forest<int> will be a friend of a Forest<double>, which might not be what you need. @Alex proposal in the comment will only make a particular instantiation of the template a friend, which is probably closer to what you want, but you need to declare the templated operator before the template class, and for that you will need to forward declare the template class...

A common pattern for friend free functions in templates is defining the function in place:

template <typename T>
class Forest {
   // ...
   friend Forest& operator+( Forest const & lhs, Forest const & rhs ) [1]
   {
       // implementation here
   }
}
// [1] Note that the arguments are const references (read only), and also note that
//     you do not need to provide the type argument inside the template declaration

This allows you to define it as a non templated function and at the same time have the compiler instantiate the function for you. Also, it is usually simpler to also define member methods inlined in the class definition when dealing with templates. It makes life simpler, and after all in most cases you do need to provide the implementation in the (same) header file.

Yet, when defining binary operators a better approach is to define operator+= as a member method, and then you can easily define operator+ as a non-friend free function. The pattern would be:

struct test {
   test& operator+=( test const & );
};
test operator+( test lhs, test const & rhs ) { // [2]
   lhs += rhs;
   return lhs;
}
// [2] Note that the first argument is by value, and the second by const reference
//     This means that the compiler will copy the first argument for you, and you
//     are free to modify it with the += operator and return the copy.

Now, the most tricky part is mixing the previous two advices. To be able to define operator+ that is a free function inside the template definition, a common trick is to make it friend even if that is not required for access reasons:

template <typename T>
class Forest {
   Forest& operator+=( Forest const & ) {
      // implemenation
   }
   friend Forest operator+( Forest lhs, Forest const & rhs ) { // [3]
      return lhs+=rhs;
   }
};
// [3] friendship only to allow us to define the free function inside the template
//     declaration.
David Rodríguez - dribeas
joedillian
It then goes on to list every instance of a >> operator in the basic_istream class.
joedillian
I can't get my head across the three candidates listed by the compiler.
Chubsdad
David Rodríguez - dribeas
Ahh, that does make things a bit easier. I would take your advice on the += thing, as I have read this before, but my professors requirements specifically ask us to delete the operands of the + operator. For some ungodly reason.
joedillian
@joedillian: as to the errors that you are getting now, it is quite hard to try to guess from what we understand to be the modified version of it. Try writting a simple test case as in: `template <typename T> class test { friend std::istream return i; } }; int main() { test t; std::cin >> t; }` and see if you can reproduce the problem. If that does not reproduce the problem, enlarge bits of it to make it closer to your problem. At one point you will notice something stupid like a typo or such... If not, ask with the simplified code.
David Rodríguez - dribeas
Basically David, it doesn't recognize my template<NODETYPE> friend istream" where file is of type istream and charForest is of type Forest<char>.
joedillian