I have a template with an overloaded friend operator. It works well, but if there is another unrelated but similar operator within a scope, it does not compile: g++ produces strange error, and a similar errors are produced by icc and MSVC.
The code is:
template <class Type> class product {};
template <> class product<double> { public: typedef double type; };
template<class Type> class product2 {
public: typedef typename product<Type>::type type;
};
//------------
template <class Cmpt> class Tensor { };
template <class Cmpt>
typename product2<Cmpt>::type operator&
(const Tensor<Cmpt>& a, const Tensor<Cmpt>& b)
{ return 0; } // [1]
//template <class Cmpt>
//typename product<Cmpt>::type operator&
//(const Tensor<Cmpt>& a, const Tensor<Cmpt>& b)
//{ return 0; }
//-----
template<class Type> class fvMatrix;
template<class Type>
fvMatrix<Type> operator&
(const fvMatrix<Type>& a, const fvMatrix<Type>& b)
{ return a; }
template <class Type> class fvMatrix {
friend fvMatrix<Type> operator& <Type>
(const fvMatrix<Type>& a, const fvMatrix<Type>& b);
};
//----------
int main() {
fvMatrix<int> m;
m & m;
return 0;
}
The error by gcc 4.8.1 is (similar for 4.8.0 and 4.7.2):
c.cpp: In instantiation of 'class product2<int>':
c.cpp:13:31: required by substitution of 'template<class Cmpt> typename product2<Type>::type operator&(const Tensor<Cmpt>&, const Tensor<Cmpt>&) [with Cmpt = int]'
c.cpp:32:27: required from 'class fvMatrix<int>'
c.cpp:39:17: required from here
c.cpp:5:50: error: no type named 'type' in 'class product<int>'
public: typedef typename product<Type>::type type;
Similar errors (that is, attempting to use product<int>::type
via operator&
for Tensor<int>
) are produced by icc and MSVC.
If I change the code so that product
is used instead or product2
in operator&
for Tensor
(uncomment the commented lines and comment operator [1]), the code compiles.
If I completely remove class Tensor
with its operator&
, the code compiles.
UPDATE: completely removing m&m;
line still leaves code not compiling.
I see that many sources suggest writing friend fvMatrix<Type> operator& <>
, i.e. without Type
between <>
(http://www.parashift.com/c++-faq-lite/template-friends.html, C++ template friend operator overloading), and this indeed solves this problem.
However, even the review at https://stackoverflow.com/a/4661372/3216312 uses friend std::ostream& operator<< <T>
So, the question is: why does the above code not compile? Is writing friend fvMatrix<Type> operator& <Type>
wrong and why?
Background: we are modifying OpenFOAM framework and ran into such a problem inside the original OpenFOAM code which uses friend ... operator& <Type>
(http://foam.sourceforge.net/docs/cpp/a04795_source.html, line 484).