Здравствуйте, syvyi, Вы писали:
S>Почему не компилируется. Объяснить.
Затруднюсь сказать, как правильно написать шаблон свободной функции, принимающей вложенный класс шаблонного класса. Может быть, что вообще никак.
А вот как исправить — пожалуйста.
template<int N>
class A
{
public:
class B
{
int x;
std::vector<char> y;
public:
void swap(B& other); // во-первых, пригодится; во-вторых, иллюстрация, как вынести код за объявление классаfriend void swap(B& lhs, B& rhs) { lhs.swap(rhs); } // тоже пригодится, хотя это исключительно для ADL
};
};
template<int N> void A<N>::B::swap(B& other) // этот код можно было и проинлайнить в объявлении класса
{
using std::swap; // чтобы помочь ADL - знать, где искать
swap(x, other.x);
swap(y, other.y);
}
namespace std
{
template<int N> void swap(typename ::A<N>::B& lhs, typename ::A<N>::B& rhs) // это перегрузка, а не специализация
{
lhs.swap(rhs);
}
}
int main()
{
A<1>::B p, q;
swap(p,q); // это колдунство, основанное на тонком месте, если не сказать - дефекте, стандарта (функция swap лежит ни в ::, ни в std::)
std::swap(p,q);
}
Складывается впечатление, что ты троллишь, потому что твой пример выглядит как сборник избитых замусоленных тем:
Специализацию шаблонной функции std::swap, которую ты объявляешь дружественной классу b не возможно определить (и даже объявить) за пределами шаблонного класса a, поскольку она является зависимой от шаблонного параметра и за пределами этого шаблонного класса эта специализация не может быть полной, а частичные специализации для шаблонных функций, как известно, никогда не поддерживались и не поддерживаются сейчас. Это замусоленная тема номер раз;
Как следствие, определение этой специализации также невозможно сделать внутри классов a и b, поскольку согласно стандарту, в случаях, когда определение явной специализации выполняется за пределами пространства имен, в котором объявлен основной шаблон (std в данном случае), эта специализация должна быть предварительно объявлена в этом пространстве имен. Это замусоленная тема номер два;
Невозможность определения дружественной функции является хорошей иллюстрацией того, почему не нужно злоупотреблять вложенностью классов. Это замусоленная тема номер три;
Перегруженная шаблонная функция swap, которую ты определяешь ниже в пространстве имен std, не является дружественной классу a<>::b, поскольку не соответствует объявленной ранее дружественной специализации;
Автовыведение типов параметров не будет работать для этой шаблонной функции, поскольку компиляторы не могут выводить внешний тип по внутреннему. Это еще одна избитая тема;
Конструкции вида:
a<>::b o1();
a<>::b o2();
давно уже стали притчей во языцех, поскольку не являются определением локальных переменных, а являются объявлением глобальных функций.
Ты специально что ли собирал все эти грабли в один сарай?
--
Не можешь достичь желаемого — пожелай достигнутого.
Неа, не взлетит. Я помню, тебе уже неоднократно приходилось разбирать и разъяснять подобные случаи. Не может компилятор для этой перегрузки автоматически вывести шаблонный параметр N: http://ideone.com/3WqFlE. А твой предыдущий пример компилируется за счет того, что вместо этой перегрузки выбирается стандартный swap<T>(T&,T&) из библиотеки.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, rg45, Вы писали:
R>...А твой предыдущий пример компилируется за счет того, что вместо этой перегрузки выбирается стандартный swap<T>(T&,T&) из библиотеки.
Вот она, обратная сторона SFINAE
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, rg45, Вы писали:
R>Неа, не взлетит. Я помню, тебе уже неоднократно приходилось разбирать и разъяснять подобные случаи. Не может компилятор для этой перегрузки автоматически вывести шаблонный параметр N: http://ideone.com/3WqFlE. А твой предыдущий пример компилируется за счет того, что вместо этой перегрузки выбирается стандартный swap<T>(T&,T&) из библиотеки.
Ай, блин, точно.
Тогда остаётся последний, военный способ.
В местах вызовов вместо std::swap(p,q); писать using std::swap; swap(p,q); — чтобы работал ADL и вызывалась френд-функция, живущая в трещине между мирами.