Наверное, раньше задавали вопрос, но все это приближается к пределу моего понимания и понимания С++, поэтому я немного замешкаюсь, понимая, о чем говорят и что именно происходит. Позвольте мне просто перейти прямо к коду. Это работает:
template <typename T>
class Foo
{
    struct Bar
    {
        Bar() {}
        ~Bar() noexcept {}
        Bar(Bar&& b) : Bar() { swap(*this, b); }
        friend void swap(Bar& b1, Bar& b2) { /* ... */ }
    };
};
template class Foo<int>; // explicit instantiation of Foo with int type
Но как перенести определение swap вне тела структуры Bar? Если я это сделаю:
template <typename T>
class Foo {
    struct Bar {
        // ...
        Bar(Bar&& b) : Bar() { swap(*this, b); } // line 16
        // ...
        template <typename V>
          friend void swap(typename Foo<V>::Bar&, typename Foo<V>::Bar&);
    };
};
template <typename T>
  void swap(typename Foo<T>::Bar& b1, typename Foo<T>::Bar& b2) {} // line 26
template class Foo<int>; // line 31
g++ (4.7.1, flags: -Wall -std = С++ 11) сообщает:
main.cpp: In instantiation of ‘Foo<T>::Bar::Bar(Foo<T>::Bar&&) 
            [with T = int; Foo<T>::Bar = Foo<int>::Bar]’:
main.cpp:31:16:   required from here
main.cpp:16:28: error: no matching function for call to 
            ‘swap(Foo<int>::Bar&, Foo<int>::Bar&)’
main.cpp:16:28: note: candidate is:
main.cpp:26:6: note: template<class T> void swap(typename Foo<T>::Bar&, 
                                                 typename Foo<T>::Bar&)
main.cpp:26:6: note:   template argument deduction/substitution failed:
main.cpp:16:28: note:   couldn't deduce template parameter ‘T’
Я предполагаю, что код для swap также должен быть создан при явном экземпляре Foo, что имеет смысл, но почему компилятор не может определить, что swap(Foo<int>::Bar&...) необходимо создать? Почему смена шаблона не выполняется? Или у меня все не так?
ОБНОВЛЕНИЕ 1
С
template <typename T> class Foo;
template <typename T>
  void swap(typename Foo<T>::Bar& b1, typename Foo<T>::Bar& b2);
template <typename T>
class Foo {
    struct Bar {
      Bar(Bar&& b) : Bar() { swap(*this, b); }  // line 19
      friend void swap<>(Foo<T>::Bar& b1, Foo<T>::Bar& b2); // line 20
    };
};
template <typename T>
  void swap(typename Foo<T>::Bar& b1, typename Foo<T>::Bar& b2) {} // line 26
template class Foo<int>; // line 29
g++ (4.7.1, flags: -Wall -std = С++ 11) сообщает:
main.cpp: In instantiation of ‘struct Foo<int>::Bar’:
main.cpp:29:16:   required from here
main.cpp:20:17: error: template-id ‘swap<>’ for ‘void swap(Foo<int>::Bar&, Foo<int>::Bar&)’ does not match any template declaration
main.cpp: In instantiation of ‘Foo<T>::Bar::Bar(Foo<T>::Bar&&) [with T = int; Foo<T>::Bar = Foo<int>::Bar]’:
main.cpp:29:16:   required from here
main.cpp:19:24: error: no matching function for call to ‘Foo<int>::Bar::Bar()’
main.cpp:19:24: note: candidate is:
main.cpp:19:5: note: Foo<T>::Bar::Bar(Foo<T>::Bar&&) [with T = int; Foo<T>::Bar = Foo<int>::Bar]
main.cpp:19:5: note:   candidate expects 1 argument, 0 provided
main.cpp:19:28: error: no matching function for call to ‘swap(Foo<int>::Bar&, Foo<int>::Bar&)’
main.cpp:19:28: note: candidate is:
main.cpp:26:8: note: template<class T> void swap(typename Foo<T>::Bar&, typename Foo<T>::Bar&)
main.cpp:26:8: note:   template argument deduction/substitution failed:
main.cpp:19:28: note:   couldn't deduce template parameter ‘T’
ОБНОВЛЕНИЕ 2
ОК, так что это невозможно. Piotr связал с вывод вложенного класса внутри шаблона, но я не понимаю ответа. Почему не может быть swap определено вне его объявления? Насколько я (неправильно) понимаю вещи, почему компилятор не может создать код для swap(Foo<int>::Bar&...) и ссылаться на него в коде для явного создания Foo<int>? Неужели я совершенно не понял, что происходит? В чем проблема?
ОБНОВЛЕНИЕ 3
ОК, это невозможно сделать, потому что, если существуют специализированные шаблоны, компилятор не может гарантировать, что вызовы swap, определенные вне Foo, недвусмысленны, поскольку Foo<some_class>::Bar может быть чем-то совершенно иным в конкретной специализации. Надеюсь, я прав. Но почему g++ не предупреждает об этом, прежде чем я создам явное создание Foo?
template <typename T>
class Foo {
    struct Bar {
        // ...
        Bar(Bar&& b) : Bar() { swap(*this, b); }
        // ...
        template <typename V>
          friend void swap(typename Foo<V>::Bar&, typename Foo<V>::Bar&);
    };
};
template <typename T>
  void swap(typename Foo<T>::Bar& b1, typename Foo<T>::Bar& b2) {}
//template class Foo<int>; // let comment this explicit instantiation out.
Этот код компилирует fine (g++ 4.7.1, flags: -Wall -std = С++ 11). Но не следует ли мне предупреждать меня, что этот код может вызвать проблемы? Когда я добавляю явное создание Foo, проблема заключается не в самой строке, а в коде swap, реализованном вне Foo.