You should put the code /in the question/.
------------------------------------------------------------------------------------------------
#include <iostream>
template<typename T>
class Test;
template<typename T>
Test<T> operator + (const Test<T>& lhs, const Test<T>& rhs);
template<typename T>
class Test
{
// this "friend" compiles
//friend Test<T> operator + <T> (const Test<T>& lhs, const Test<T>& rhs);
public:
explicit Test(T value)
: m_value(value)
{
}
// we comment this operator then it compiles
Test operator + (T value)
{
return Test(m_value + value);
}
private:
// this "friend" doesn't compile
friend Test<T> operator + <T> (const Test<T>& lhs, const Test<T>& rhs);
// this "friend" compiles
//friend Test<T> operator + (const Test<T>& lhs, const Test<T>& rhs)
//{
// return Test<int>(lhs.m_value + rhs.m_value);
//}
T m_value;
};
template<typename T>
Test<T> operator + (const Test<T>& lhs, const Test<T>& rhs)
{
return Test<T>(lhs.m_value + rhs.m_value);
}
main(int argc, char* argv[])
{
Test<int> t1(5);
Test<int> t2(6);
Test<int> t3 = t1 + t2;
}...................................................................................................
Note that since `main` lack a return value specification this code is
invalid as standard C++, and Visual C++ does not compile it.
g++ /should/ diagnose this by default, but MinGW g++ 8.2.0 doesn't even
warn when I explicitly enable the warning,
http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wreturn-type
> I tried gcc and ms vc++. They both have very similar errors.
You should specify the build command(s) /in the question/.
$ g++ prog.cc -Wall -Wextra
-I/opt/wandbox/boost-1.69.0/gcc-8.2.0/include -std=gnu++2a
Instead of a gcc-specific cryptic specification of standard like
"gnu++2a", which could mean anything, use e.g. "c++14".
> What is strange that if we move friend expression before declaring
> any class members then code compiles fine. Or we can remove member
> operator then it compiles too.
Well,
friend Test<T> operator + <T>
is a syntax error.
When you fix that by removing the last `<T>`, g++ helpfully reports that it
"declares a non-template function"
When you fix /that/, by templating the `friend` declaration,
template< class U >
friend Test<U> operator + (const Test<U>& lhs, const Test<U>& rhs);
it compiles.
You then have /two/ operator+ definitions. However, the one inline in
the class has right hand side argument of type `T`, so it's not
considered for the call in `main`. So you get a call of the free function.
When you fix that it still compiles, because the lookup rules are such
that when a definition (or more generally a declaration) is found in the
class, declarations at namespace level are not considered. I.e. you then
get a call of the member version. And I suggest that you just remove
that, because the free function supports implicit conversion in both
argument positions, so it's the more general variant.
Cheers & hth.,
- Alf