おそらく以前に尋ねられたかもしれませんが、これはすべてC ++の理解と認識の限界に近づいているので、何が話されているのか、正確に何が起こっているのかを理解するのが少し遅いです。コードに直接ジャンプしましょう。これは機能します:
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、フラグ:-Wall -std = c ++ 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、フラグ:-Wall -std = c ++ 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
OK、これはできません。Piotrはテンプレート内のネストされたクラスの出力にリンクしていますが、答えがわかりません。swap
宣言の外で定義できないのはなぜですか?私が(誤)理解している限り、コンパイラがコードを作成swap(Foo<int>::Bar&...)
して、コード内でリンクして、明示的にインスタンス化できないのはなぜFoo<int>
ですか?私は何が起こっているのか完全に誤解しましたか?どうしたの?
更新3
OK、これはできません。テンプレートスペシャライゼーションがある場合、コンパイラは、特定のスペシャライゼーションではまったく異なる可能性があるため、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's comment this explicit instantiation out.
このコードは正常にコンパイルされます(g ++ 4.7.1、フラグ:-Wall -std = c ++ 11)。しかし、このコードが問題を引き起こす可能性があることを警告するべきではありませんか?の明示的なインスタンス化を追加するとFoo
、問題はその行自体ではなく、のswap
外部に実装されたコードにありFoo
ます。