Operator as non-function

S

saneman

In a .h file I have:

friend iterator operator + <> (difference_type i, const iterator& it);

and outside the class I have:

template<class A>
hat_iterator<A> operator + (typename A::difference_type i,
const hat_iterator<A>& it) {
return hat_iterator<A>(it._pos + i, it._hat);
}



But when I compile I get:

error: declaration of ‘operator+’ as non-function

Is it a wrong definition?
 
V

Victor Bazarov

saneman said:
In a .h file I have:

friend iterator operator + <> (difference_type i, const iterator& it);

and outside the class I have:

template<class A>
hat_iterator<A> operator + (typename A::difference_type i,
const hat_iterator<A>& it) {
return hat_iterator<A>(it._pos + i, it._hat);
}



But when I compile I get:

error: declaration of ‘operator+’ as non-function

Is it a wrong definition?

Depends on the declaration. Post _complete_ code. Remove all parts
that are irrelevant, but keep the code compilable.

V
 
K

kwikius

In a .h file I have:

friend iterator operator + <> (difference_type i, const iterator& it);

and outside the class I have:

   template<class A>
   hat_iterator<A> operator + (typename A::difference_type i,

I think the problem is that the arg i is a dependent type, IOW it has
nothing to do with operator as such.

regards
Andy Little
 
S

saneman

Victor said:
Depends on the declaration. Post _complete_ code. Remove all parts
that are irrelevant, but keep the code compilable.

V

The below code:

template <class A>
class BOB {
private:
typedef BOB<A> iterator;
public:
typedef typename A::difference_type difference_type;
friend iterator operator + <> (difference_type i, const iterator& it);
};

Gives the error:

hat_iterator.h:11: error: declaration of ‘operator+’ as non-function
hat_iterator.h:11: error: expected ‘;’ before ‘<’ token


But both arguments have been typedefed so I cannot see where the error is.
 
J

James Kanze

The below code:
template <class A>
class BOB {
private:
typedef BOB<A> iterator;
public:
typedef typename A::difference_type difference_type;
friend iterator operator + <> (difference_type i, const iterator& it);
};
Gives the error:
hat_iterator.h:11: error: declaration of ?operator+? as non-function
hat_iterator.h:11: error: expected ?;? before ?<? token
But both arguments have been typedefed so I cannot see where
the error is.

The problem is that the compiler doesn't know that the operator+
in question is (or might be) a template, and so interprets the <
after it as less than. You need a declaration of the operator+
in scope before defining the class. Something like:

template< class A > class BOB ;
template< class A > BOB<A> operator+(
typename BOB<A>::difference_type,
BOB<A> const& ) ;

before your class template definition.

I'm not sure, but I think your friend declaration should also
be:
friend iterator operator + <A> (difference_type i, const iterator&
it);

g++ accepts it either way, however. (I'm not sure what the
relationship between BOB and hat_iterator is, however.)
 
S

saneman

James said:
The problem is that the compiler doesn't know that the operator+
in question is (or might be) a template, and so interprets the <
after it as less than. You need a declaration of the operator+
in scope before defining the class. Something like:

template< class A > class BOB ;
template< class A > BOB<A> operator+(
typename BOB<A>::difference_type,
BOB<A> const& ) ;

before your class template definition.

I'm not sure, but I think your friend declaration should also
be:
friend iterator operator + <A> (difference_type i, const iterator&
it);

g++ accepts it either way, however. (I'm not sure what the
relationship between BOB and hat_iterator is, however.)


--
James Kanze (GABI Software) email:[email protected]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Ok this version below works as you recommended:

template< class A > class BOB;
template< class A >
BOB<A> operator+(typename BOB<A>::difference_type, BOB<A> const& );


template <class A>
class BOB {
private:
typedef BOB<A> iterator;
public:
typedef typename A::difference_type difference_type;
friend iterator operator + <> (difference_type i, const
iterator& it);

};


But I don't understand the first 3 lines. In Bjarne Stroustrup C++PL
C.13.2 page 854 he writes the following example:


template <class T> class Matrix;
template <class T> class Vector {
T v[4];
public:
friend Vector operator *<> (const Matrix<T>&, const Vector&);

};


So it seems that it should not be necessary to declare the operator as a
template operator.

I have C++ Templates by David Vandevoorde, but there is no info on this
special rule, is there some documentation on the theory behind this example?
 
V

Victor Bazarov

saneman said:
Ok this version below works as you recommended:

template< class A > class BOB;
template< class A >
BOB<A> operator+(typename BOB<A>::difference_type, BOB<A> const& );


template <class A>
class BOB {
private:
typedef BOB<A> iterator;
public:
typedef typename A::difference_type difference_type;
friend iterator operator + <> (difference_type i, const
iterator& it);

};


But I don't understand the first 3 lines.

The first 3 lines are _declarations_. They tell the compiler that
there will be (at some point) definitions of a class template BOB
with one type-argument, and a function template for 'operator+'
with certain arguments and the template type-argument. The main
reason is to declare the names (stake the claim, so to speak) and
make them belong to the global namespace.

Any subsequent use of the name 'BOB' or the operator+ *with*
template argument list (even if it's empty) would mean those are
referring to the previously declared names that live in the global
namespace.
In Bjarne Stroustrup C++PL
C.13.2 page 854 he writes the following example:


template <class T> class Matrix;
template <class T> class Vector {
T v[4];
public:
friend Vector operator *<> (const Matrix<T>&, const Vector&);

};


So it seems that it should not be necessary to declare the operator
as a template operator.

It is entirely possible that the requirements have changed since
the time of publishing of the copy you have. The name lookup rules
are not simple and in some cases, especially with templates, you
need to have the template declaration in the scope before you can
refer to it. I do not remember if declaring an instantiation of
a template function a friend is one of those cases.
I have C++ Templates by David Vandevoorde, but there is no info on
this special rule, is there some documentation on the theory behind
this example?

The Standard.

V
 
S

saneman

But if I try to overload the + operator I get the same error:



template< class A > class BOB;
template< class A >
BOB<A> operator+(typename BOB<A>::difference_type, BOB<A> const& );


template <class A>
class BOB {
private:
typedef BOB<A> iterator;
public:
typedef typename A::difference_type difference_type;
friend iterator operator + <> (difference_type i, const
iterator& it);

// Added overload of + operator
iterator operator + (const difference_type i) const {
return iterator(1);
}

};


When Compiling I get:

error: declaration of ‘operator+’ as non-function
error: expected ‘;’ before ‘<’ token

Where the error refers to:


friend iterator operator + <> (difference_type i, const
iterator& it);


Does that mean that overloading of template operators are impossible?
 
V

Victor Bazarov

saneman said:
But if I try to overload the + operator I get the same error:



template< class A > class BOB;
template< class A >
BOB<A> operator+(typename BOB<A>::difference_type, BOB<A> const& );


template <class A>
class BOB {
private:
typedef BOB<A> iterator;
public:
typedef typename A::difference_type difference_type;
friend iterator operator + <> (difference_type i, const
iterator& it);

// Added overload of + operator
iterator operator + (const difference_type i) const {
return iterator(1);
}

};


When Compiling I get:

error: declaration of ‘operator+’ as non-function
error: expected ‘;’ before ‘<’ token

Where the error refers to:


friend iterator operator + <> (difference_type i, const
iterator& it);


Does that mean that overloading of template operators are impossible?

Take your code to another compiler and see how they react. One of
the most compliant when it comes to templates is Comeau C++. They
have the online trial version. Use it. See what it says. I would
do it myself, but you didn't post the entire code, did you? If I
take what you posted, Comeau compiles it OK.

V
 
J

James Kanze

Ok this version below works as you recommended:
template< class A > class BOB;
template< class A >
BOB<A> operator+(typename BOB<A>::difference_type, BOB<A> const& );
template <class A>
class BOB {
private:
typedef BOB<A> iterator;
public:
typedef typename A::difference_type difference_type;
friend iterator operator + <> (difference_type i, const iterator& it);
};
But I don't understand the first 3 lines.

Just declarations, so that the symbols are known to the
compiler. You need to declare the operator+ function, so that
the compiler knows it is a template, and you need to declare the
class template BOB, in order to refer to it in the operator+
functions.
In Bjarne Stroustrup C++PL
C.13.2 page 854 he writes the following example:
template <class T> class Matrix;
template <class T> class Vector {
T v[4];
public:
friend Vector operator *<> (const Matrix<T>&, const Vector&);
};
So it seems that it should not be necessary to declare the
operator as a template operator.

I thought you wanted it to be a template. If you don't, drop
the said:
I have C++ Templates by David Vandevoorde, but there is no
info on this special rule, is there some documentation on the
theory behind this example?

It's not a special rule, as far as I can see. The compiler
parses templates in two phases. In order to do so successfully,
it must know what symbols are templates, and what symbols are
the names of types---the grammar of C++ isn't context free.
That's why if the symbol is dependent, and unknown at the
point of use, you must tell the compiler that it is a template
or a typename. In this case, it's a little more complex,
because the symbol occurs in a context where preceding it by the
keyword "template" would cause ambiguities, or mean something
else. So you must declare is somewhere so that the compiler
will recognize it as a template.

Quite frankly, I wouldn't bother. I'd write a named member
function to do what I wanted, and then define the operator as a
template after, to call the named member function. So there'd
be no need of making it a friend.
 
J

James Kanze

But if I try to overload the + operator I get the same error:
template< class A > class BOB;
template< class A >
BOB<A> operator+(typename BOB<A>::difference_type, BOB<A> const& );
template <class A>
class BOB {
private:
typedef BOB<A> iterator;
public:
typedef typename A::difference_type difference_type;
friend iterator operator + <> (difference_type i, const
iterator& it);

// Added overload of + operator
iterator operator + (const difference_type i) const {
return iterator(1);
}

};
When Compiling I get:
error: declaration of 'operator+' as non-function
error: expected ';' before '<' token
Where the error refers to:
friend iterator operator + <> (difference_type i, const
iterator& it);

Just a guess, but the operator+ member is hiding the global
operator+ template declaration, so once again, the compiler
doesn't know that it is dealing with a template.
Does that mean that overloading of template operators are impossible?

Not at all, but name lookup for operators is a bit special. I
find it good practice to define most operators as just calling
named functions, putting all of the binary operators in global
scope. (The one exception would be the assignment operators.)

From what you've posted, I gather that BOB<A> is in fact an
iterator (into itself?). A random access iterator, since it
supports addition of a difference_type. What's wrong with
defining a member operator+=, and then, after the class template
definition:

template< typename A >
BOB<A>
operator+( BOB<A> const& lhs,
typename BOB<A>::difference_type rhs )
{
BOB<A> result( lhs ) ;
result += rhs ;
return result ;
}

template< typename A >
BOB<A>
operator+( typename BOB<A>::difference_type lhs,
BOB<A> const& rhs,
{
BOB<A> result( rhs ) ;
result += lhs ;
return result ;
}

Or having defined operator+=, add the following two definitions
directly in the class:

friend iterator
operator+( iterator const& lhs, difference_type rhs )
{
BOB<A> result( lhs ) ;
result += rhs ;
return result ;
}

friend iterator
operator+( difference_type rhs, iterator const& lhs )
{
BOB<A> result( rhs ) ;
result += lhs ;
return result ;
}

(In the above, the keyword friend is used to allow defining the
functions in the class without making them members, and not to
allow access to private members. The Barton and Nackman trick.)

FWIW: I usually provide such operators by inheriting from a
class template which defines them, as above. So all I'd have to
write is:

template< typename A >
class BOB
: public Gabi::MixedArithmeticOperators< BOB< A >,
typename A::difference_type >
{
// ...
// but with a public +=( difference_type )
} ;

The case comes up so often, it's worth having a generic
solution.
 
S

saneman

Victor said:
Take your code to another compiler and see how they react. One of
the most compliant when it comes to templates is Comeau C++. They
have the online trial version. Use it. See what it says. I would
do it myself, but you didn't post the entire code, did you? If I
take what you posted, Comeau compiles it OK.

V


I have now tried it on 3 different machines with the same error. The
test program consist of test.h I compile with:

g++ test.h

And the error on all machines are:

test.h:16: error: declaration of 'operator+' as non-function
test.h:16: error: expected ';' before '<' token


Below are the exact content of test.h:

template <class A> class BOB;
template<class A>
BOB<A> operator + (typename BOB<A>::difference_type, BOB<A> const&);

template <class A>
class BOB {
private:
typedef BOB<A> iterator;
public:
typedef typename A::difference_type difference_type;

iterator operator + (const difference_type i) const {
return iterator(1);
}

friend iterator operator + <> (difference_type i, const iterator& it);
};


But maybe this kind of code is only meant to run with Comeau.
 
S

saneman

saneman said:
I have now tried it on 3 different machines with the same error. The
test program consist of test.h I compile with:

g++ test.h

And the error on all machines are:

test.h:16: error: declaration of 'operator+' as non-function
test.h:16: error: expected ';' before '<' token


Below are the exact content of test.h:

template <class A> class BOB;
template<class A>
BOB<A> operator + (typename BOB<A>::difference_type, BOB<A> const&);

template <class A>
class BOB {
private:
typedef BOB<A> iterator;
public:
typedef typename A::difference_type difference_type;

iterator operator + (const difference_type i) const {
return iterator(1);
}

friend iterator operator + <> (difference_type i, const iterator& it);
};


But maybe this kind of code is only meant to run with Comeau.


This is wierd. In BOB, if I switch the template operator with the
non-template operator it works!


template <class A>
class BOB {
private:
typedef BOB<A> iterator;
public:
typedef typename A::difference_type difference_type;


// Non-member template operator declared first!!
friend iterator operator + <> (difference_type i, const iterator& it);

// member declared last!!
iterator operator + (const difference_type i) const {
return iterator(1);
}


};



I made the same on the class without using templates and there the order
did not matter. Is the another template voodoo thing?
 
J

James Kanze

saneman wrote:

[...]
This is wierd. In BOB, if I switch the template operator with the
non-template operator it works!
template <class A>
class BOB {
private:
typedef BOB<A> iterator;
public:
typedef typename A::difference_type difference_type;
// Non-member template operator declared first!!
friend iterator operator + <> (difference_type i, const iterator& it);
// member declared last!!
iterator operator + (const difference_type i) const {
return iterator(1);
}
};
I made the same on the class without using templates and there
the order did not matter. Is the another template voodoo
thing?

Just the way the compiler implements name lookup. If it hasn't
seen the member declaration of operator+ yet, it finds the gobal
one, and knows that it is a template.

This may be an error in the compiler. I'm not going to waste my
time trying to figure it out, however, because it really doesn't
change anything. You have to program to the compilers you work
with, and the problem is easily solved in a way that shouldn't
trigger any compiler probles, as I pointed out in my postings.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,071
Latest member
MetabolicSolutionsKeto

Latest Threads

Top