2

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!

felix
  • 175
  • 4
  • 1
    Its a problem with SunStudio, it is quite bad. Looking at the boost sources reveals many ideas on how to work around things for it. – PlasmaHH Oct 14 '11 at 15:43
  • Thanks, I'll check out the boost sources then. – felix Oct 15 '11 at 09:45
  • I've been browsing a bit in the boost sources, it seems to me that the most effective way to solve this problem is by using `#ifdef`: on Sun Studio (and other compilers where this does not work), simply make the needed things `public` instead of `protected` or `private`, and remove the `friend` statements. – felix Oct 16 '11 at 20:51
  • Since M::f() is public, why do you need a friend declaration at all? – Stephen Gross Oct 18 '11 at 19:46
  • My "real" template where this problem appeared had some private data which ::f() was using as well. – felix Oct 19 '11 at 07:51

2 Answers2

3

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 {};
Maksim Kulagin
  • 146
  • 1
  • 3
  • re: your 2nd answer, I've encountered a rather strange situation while attempting to build boost. The code resembles: `template class A; template class A { template class impl; template friend class impl; template class impl { }; /* ... */` ... where that nested `impl` class gets the `Multiple declaration...` error. The only way I've found to resolve it is to remove the forward declaration and move the friend statement to after the class body. – Brian Vandenberg Sep 23 '13 at 20:59
0

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.
Mark B
  • 95,107
  • 10
  • 109
  • 188