1

I have some (simple looking?) problem with the variable declaration in template friend operator overloading. The compiler gives me a message:

main.cpp|103|error: ‘ptemp’ was not declared in this scope|

Code:

template <typename K, typename I>
class Sequence
    {
    private:
         struct Data
         {
            K key;
            I data;
            Data *pnext;
          };

     Data *pHead;
    public:
    //(...)
    friend ostream &operator << <I,K> (ostream&, const Sequence<I,K>&);
    };



    template <typename I, typename K>
    ostream &operator << (ostream& stream, const Sequence<I,K> &cop)
    {
     Sequence<I,K>::Data *ptemp (cop.pHead); ///here is the error (?)

        stream << "-------------- PRINT BEGINS ---------------" << endl;
        if (!ptemp) //there is no elements
        {
        stream << "The list is empty, there is nothing to print!" << endl;
        stream << "--------------  PRINT ENDS  ---------------" << endl << endl;
        return stream;
        };
    }

Compilers gives message that there is no declarated "ptemp" when I do a declaration. The same is when I erase initialization of ptemp. I can't understand what is wrong in this declaration. I will be grateful for any suggestions.

juniorro
  • 47
  • 3
  • Try using `Sequence::Data *ptemp = cop.pHead;` – bialpio Nov 11 '14 at 21:02
  • That friend declaration looks pretty funky. Are you sure you're not getting any errors from it? Also slightly worrying is that you seem to flip the order of the template parameters. – molbdnilo Nov 11 '14 at 21:24
  • Not precisely a duplicate but definitely worth reading: [Where and why do I have to put the “template” and “typename” keywords?](http://stackoverflow.com/q/610245/592323) – leemes Nov 11 '14 at 21:26

3 Answers3

3

Try the following

typename Sequence<I,K>::Data *ptemp (cop.pHead); 
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • It works for me, thanks :) But can you explain me why I have to use typename keyword in this specific situation, or give me some article to read about this? – juniorro Nov 11 '14 at 21:11
  • 1
    @juniorro Otherwise the name is considered as a data member instead of a type name. – Vlad from Moscow Nov 11 '14 at 21:15
  • @juniorro: `Sequence::Data` is a name that depends on a template parameter (a *dependent name*), so you need `typename` to inform the compiler that it names a type and not a value. Otherwise, the declaration would be interpreted as an expression: the multiplication of `Sequence::Data` by the function call `ptemp(cop.pHead)`! – Jon Purdy Nov 11 '14 at 21:15
2

The problem appears to be that Sequence<I,K>::Data is a dependent name and the compiler needs help from the typename keyword to know what to do. So you would need to say typename Sequence<I,K>::Data *ptemp(cop.pHead); instead. I can't figure out how it's interpreting it without the keyword though (my first guess, as a function declaration via most vexing parse doesn't appear to be correct as changing to an = in the initialization didn't fix it).

Also as an aside it appears that your inline friend declaration may be a compiler-specific extension that should probably be avoided. I had to make multiple changes to your code to get to the point of reproducing the error in the question with g++ 4.5.

Mark B
  • 95,107
  • 10
  • 109
  • 188
0

The name Sequence<I,K>::Data depends on the definition of I and K: the compiler can't know if Data is a type or a non-type (i.e. a value) in the template instance Sequence<I,K>. So you need to tell the compiler that it is a type by prepending the keyword typename, otherwise it assumes it is a non-type, so the line is parsed as a multiplication of two values, of which the second isn't known. For a detailed explanation please refer to "Where and why do I have to put the “template” and “typename” keywords?".

typename Sequence<I,K>::Data *ptemp (cop.pHead);

If you can use C++11, you can replace the full type with auto:

auto ptemp = cop.pHead;

Also, you can put the friend non-member definition directly inside the class (which does not make it a member!). Then you can refer to Sequence<I,K> simply with Sequence and to your sub-type Data simply as Data:

public:
    friend ostream &operator << (ostream& stream, const Sequence &cop)
    {
        Data *ptemp (cop.pHead);
        ...
    }
Community
  • 1
  • 1
leemes
  • 44,967
  • 21
  • 135
  • 183