шаблонный друг класса шаблона не работает в Sun Studio C++

У меня возникла проблема с присвоением классу шаблона друга-шаблона в Sun Studio. Код отлично компилируется с GNU G++ (4.4.1 и 4.4.3), но не работает с Sun Studio C++ (исправление 5.9 SunOS_sparc 124863-01 от 25 июля 2007 г.).

Вот минимальный пример:

// 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;

Когда я пытаюсь скомпилировать его через CC -c -o t3.o t3.cpp, я получаю следующие сообщения об ошибках:

"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.

Это проблема с Sun Studio C++ или это недопустимый C++ (который все еще принимается GCC и не выдает предупреждений с -Wall -pedantic)? Есть ли элегантный способ изменить код таким образом, чтобы он соответствовал стандартам и компилировался как в GCC, так и в Sun Studio?

Заранее большое спасибо!


person felix    schedule 14.10.2011    source источник
comment
Это проблема с SunStudio, это очень плохо. Глядя на источники наддува, можно найти много идей о том, как обойти это.   -  person PlasmaHH    schedule 14.10.2011
comment
Спасибо, тогда я проверю источники наддува.   -  person felix    schedule 15.10.2011
comment
Я немного просмотрел исходники буста, мне кажется, что самый эффективный способ решить эту проблему - использовать #ifdef: на Sun Studio (и других компиляторах, где это не работает), просто сделать нужные вещи public вместо protected или private и удалите операторы friend.   -  person felix    schedule 17.10.2011
comment
Поскольку M::f() является общедоступным, зачем вообще нужно объявление друга?   -  person Stephen Gross    schedule 18.10.2011
comment
В моем реальном шаблоне, где возникла эта проблема, были некоторые личные данные, которые также использовал ::f().   -  person felix    schedule 19.10.2011


Ответы (2)


Код успешно скомпилирован с использованием «CC: Sun C++ 5.8 Patch 121017-13 2008/01/02», добавив объявление шаблона другу:

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

Ниже приведен ответ не на исходный вопрос, а для тех, кто ищет, почему класс шаблона друга вызывает ошибку «Ошибка: множественное объявление для ошибки компиляции с использованием компилятора Sun CC», просто добавьте предварительное объявление для класса друга, например:

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

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

template <typename T> class B {};
person Maksim Kulagin    schedule 31.10.2011
comment
Спасибо, это действительно помогло мне. - person Hitobat; 18.07.2012
comment
Re: ваш второй ответ, я столкнулся с довольно странной ситуацией при попытке построить буст. Код выглядит так: template <typename T> class A; template <typename T, typename U> class A<T(U)> { template <typename V> class impl; template <typename V> friend class impl; template <typename V> class impl { }; /* ... */ ... где вложенный класс impl получает ошибку Multiple declaration.... Единственный способ, который я нашел, чтобы решить эту проблему, - это удалить предварительное объявление и переместить оператор друга после тела класса. - person Brian Vandenberg; 24.09.2013

Компилятор Sun, как правило, имеет некоторые проблемы и, безусловно, обновляется реже, чем такие компиляторы, как g++. В этом случае проблема, по-видимому, заключается в том, что компилятор запутался в классе, скрывающем глобальную функцию шаблона.

Я не мог найти способ напрямую решить вашу проблему здесь, но есть возможные обходные пути:

  • Просто не затеняйте глобальный шаблон в своем классе. Переименование глобального f и друга в foo, например, позволяет sun скомпилировать его. Это особенно имеет смысл, если функции не связаны между собой.
  • Избегайте необходимости в дружбе, расширив общедоступный интерфейс до M, если это кажется уместным.
person Mark B    schedule 28.10.2011