template friend of template class fails in Sun Studio C++

575 views Asked by At

I have a problem with giving a template class a template friend in Sun Studio. The code compiles fine with GNU G++ (4.4.1 and 4.4.3), but fails with Sun Studio C++ (5.9 SunOS_sparc Patch 124863-01 2007/07/25).

Here is a minimal example:

// Forward declarations
template<class T> class M;
template<class T> void f(M<T>, M<T>);

// Define M<T>
template<class T>
class M
{
public:
    void f(M<T>) { }

    friend void ::f<>(M<T>, M<T>);
};

// Define global function f
template<class T>
void f(M<T> a, M<T> b)
{
    a.f(b);
}

M<int> a;

When I try to compile it via CC -c -o t3.o t3.cpp, I get the following error messages:

"t3.cpp", line 12: Warning:  A friend function with template-id name must have a template declaration in the nearest namespace.
"t3.cpp", line 22:     Where: While specializing "M<int>".
"t3.cpp", line 22:     Where: Specialized in non-template code.
"t3.cpp", line 12: Error: Global scope has no declaration for "f".
"t3.cpp", line 22:     Where: While specializing "M<int>".
"t3.cpp", line 22:     Where: Specialized in non-template code.
1 Error(s) and 1 Warning(s) detected.

Is this a problem with Sun Studio C++, or is it invalid C++ (which is still accepted by GCC and gives no warnings with -Wall -pedantic)? Is there an elegant way to change the code such that it is standard compliant and compiles both under GCC and Sun Studio?

Thanks a lot in advance!

2

There are 2 answers

1
Maksim Kulagin On BEST ANSWER

Successfully compiled your code using "CC: Sun C++ 5.8 Patch 121017-13 2008/01/02" adding template declaration to a friend:

template<class T>
class M
{
    ...
    template <class A>
    friend void ::f(M<A>, M<A>);
    ...
};

Following is not an answer to original question but those who is looking why a friend template class causes "Error: Multiple declaration for " error compiling using Sun CC compiler, just add forward declaration for the friend class, like this:

template <typename T> class B; //will fail without forward declaration

class A
{
    private:
    template <typename T> friend class B;
};

template <typename T> class B {};
0
Mark B On

Sun's compiler does tend to have some issues and is certainly updated less frequently than compilers such as g++. In this case, the problem seems to be that the compiler gets confused by the class shadowing the global template function.

I couldn't figure out a way to directly solve your problem here, but there are possible workarounds:

  • Just don't shadow the global template in your class. Renaming the global f and friend to foo for example allows sun to compile it. This especially makes sense if the functions are unrelated.
  • Avoid the need for friendship by extending the public interface to M if that seems appropriate.