可能以前被问过,但这一切都接近我对 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
好的,所以不能这样做。Piotr已链接到Output a nested class inside a template,但我不明白答案。为什么不能swap
在其声明之外定义?据我(错误)理解,为什么编译器不能为它创建代码swap(Foo<int>::Bar&...)
并在代码中链接到它以显式实例化Foo<int>
?我完全误解了发生了什么吗?有什么问题?
更新 3
好的,这不能完成,因为如果存在模板特化,编译器不能保证对swap
定义外部的调用Foo
是明确的,因为Foo<some_class>::Bar
在特定的特化中可能是完全不同的东西。我希望我做对了。但是,为什么在我创建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
.