如何显式实例化一个模板类,它有一个具有友元函数(C ++)的嵌套类 [英] How to explicitly instantiate a template class that has a nested class with a friend function (C++)
问题描述
之前可能被问过,但所有这些都接近了我对C ++的理解和认知的极限,所以我对理解正在谈论的内容和正在发生的事情有点慢。让我直接跳到代码。这个工作原理:
template< typename T>
class Foo
{
struct Bar
{
Bar(){}
〜Bar()noexcept {}
& b):Bar(){swap(* this,b); }
friend void swap(Bar& b1,Bar& b2){/ * ... * /}
};
};
模板类Foo< int> ;; //使用int类型显式实例化Foo
但是如何移动 swap
在 Bar
结构体之外?如果我这样做:
模板< 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 = c ++ 11 )报告:
main.cpp:在实例化'Foo< T> :: Bar :: Bar(Foo< T> :: Bar&&)
[with T = int; Foo T :: :: Bar = Foo int> :: Bar]':
main.cpp:31:16:从这里需要
main.cpp:16:28:错误:无匹配函数for call to
'swap(Foo 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 / $ b main.cpp:16:28:注意:无法推导模板参数'T'
我想代码 swap
也需要创建时显式实例化 Foo
,这是有道理的,但为什么可以'编译器确定需要创建 swap(Foo
有:
p> template< typename T> 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 = c ++ 11 )报告:
main.cpp:在实例化'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&)'不匹配任何模板声明
main.cpp:在实例化'Foo< T> :: Bar :: Bar(Foo< T> :: Bar&& = int; Foo T :: :: Bar = Foo int> :: Bar]':
main.cpp:29:16:从这里需要
main.cpp:19:24:错误:无匹配函数对于调用'Foo< int> :: Bar :: Bar()'
main.cpp:19:24:note:candidate是:
main.cpp:19:5:note: T> :: Bar :: Bar(Foo T :: Bar&&)[T = int; Foo T::: Bar = Foo :: Bar]
main.cpp:19:5:note:candidate expects 1 argument,0 provided
main.cpp:19:28:error :没有匹配的函数用于调用'swap(Foo 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:模板参数扣除/替换失败:
main。 cpp:19:28:注意:无法推导出模板参数'T'
2
确定,因此无法完成。 已链接到在模板中输出嵌套类,但我不明白答案。为什么不能在其声明之外定义 swap
?至于我(mis)理解的东西,为什么不能编译器创建 swap(Foo
Foo< int>
的显式实例化代码中?我完全误解了发生了什么事吗?有什么问题?
UPDATE 3
因为如果有模板特化,编译器不能保证调用在
是明确的,因为 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> //让我们评论这个显式实例化。
这段代码编译得很好(g ++ 4.7.1,flags:-Wall -std = c ++ 11 )。但是,不应该警告我,这个代码可能会导致问题?当我添加 Foo
的显式实例化时,问题不在于该行本身,而是使用 swap
代码在 Foo
之外执行。
问题不在于 friend
。
问题是这个函数本身:
template< typename T>
void swap(typename Foo< T> :: Bar& b1,typename Foo< T> :: Bar& b2){} // line 26
无法从嵌套类中取得模板参数 T
,请参阅:在模板中输出嵌套类甚至更好这个答案: http://stackoverflow.com/a/4092248/1463922
为了说明为什么无法做到这一点,考虑这个函数:
template< class T>
void foo(typename A< T> :: Bar);
这个定义:
template< class T>
struct A {typedef int Bar; };
此电话:
int a;
foo(a);
在这个例子中 T
是什么?是 int
,因为 A< int> :: Bar
是 int $ c $因为
A< float> :: Bar
是问题是你调用
或... foo< int>(int)
或<$ c $的函数是什么函数c> foo< float>(int)
或者让示例更接近问题:
模板< class T>
struct Foo {
struct Bar {};
};
似乎编译器应该没有解决问题的方法:
模板< class T>
void resolve(typename Foo< T> :: Bar *);
但编译器甚至在这里有问题,因为它不能确定一些其他类的专门化不会使用inner其他类的struct,例如:
template< class T&
struct Foo< T *> {
typedef Foo< T> :: Bar Bar;
};
因此:
Foo< void> :: Bar b;
resolve(& b);
编译器无法知道调用哪个版本:
解析< void>(Foo< void> :: Bar *);
//或
resolve< void *>(Foo< void> :: Bar *);
// ^
建议你 - 使用内联的朋友 - 但实现它与一些其他模板类。这工作 - 但我相信这是一个有点过度设计:
模板< class S&
类ImplementSwap;
template< typename T>
class Foo {
public:
struct Bar {
int a;
Bar(){}
〜Bar(){}
friend class ImplementSwap< Foo< T>
friend void swap(Foo< T> :: Bar& b1,Foo< T> :: Bar& b2)
{ImplementSwap< Foo T> :: doSwap(b1,b2) }
Bar(Bar& b){swap(* this,b); }
};
};
template< class T>
class ImplementSwap< Foo< T>> {
public:
static void doSwap(typename Foo< T> :: Bar&,typename Foo< T> :: Bar&
};
template< class T>
void ImplementSwap< Foo< T>> :: doSwap(typename Foo< T> :: Bar&,typename Foo< T> :: Bar&)
{
// this one不是inline ....
}
我做Bar公开做这个测试:
Foo< int> :: Bar a = Foo< int> :: Bar // move constructor
int main(){
swap(a,a); // explicit swap
}
[OLD]
我以前的答案是完全错误的,第一个评论指它。
friend void swap<>(typename Foo< T> :: Bar& typename Foo< T& );
// ^^
[/ OLD]
/ p>
Probably been asked before, but all this is approaching the limit of my comprehension and cognizance of C++, so I'm a little slow in understanding what's being talked about and exactly what's going on. Let me just jump straight to the code. This works:
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
But how do I move the definition of swap
outside of the Bar
struct body? If I do this:
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=c++11) reports:
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’
I guess the code for swap
also needs to be created when explicitly instantiating Foo
, which makes sense, but why can't the compiler figure out that swap(Foo<int>::Bar&...)
needs to be created? Why does the template substitution fail? Or have I got everything wrong?
UPDATE 1
With:
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=c++11) reports:
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’
UPDATE 2
OK, so this can't be done. Piotr has linked to Output a nested class inside a template, but I don't understand the answer. Why can't swap
be defined outside its declaration? As far as I (mis)understand things, why can't the compiler create code for swap(Foo<int>::Bar&...)
and link to it in the code for the explicit instantiation of Foo<int>
? Have I totally misunderstood what's going on? What's the problem?
UPDATE 3
OK, this can't be done because if there are template specializations the compiler can't guarantee calls to swap
defined outside of Foo
are unambiguous since Foo<some_class>::Bar
might be something completely different in a particular specialization. I hope I've got that right. But, why doesn't g++ warn me about this before I create an explicit instantiation of 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.
This code compiles fine (g++ 4.7.1, flags: -Wall -std=c++11). But, shouldn't it warn me that this code could possibly cause problems? When I add the explicit instantiation of Foo
, the problem isn't with that line itself, but with the swap
code implemented outside of Foo
.
The problem is not with friend
.
The problem is with this function itself:
template <typename T>
void swap(typename Foo<T>::Bar& b1, typename Foo<T>::Bar& b2) {} // line 26
Deducing template parameter T
from nested class is not possible, see: Output a nested class inside a template or even better this answer: http://stackoverflow.com/a/4092248/1463922
To give example why it cannot be done, consider this function:
template <class T>
void foo(typename A<T>::Bar);
And this A definition:
template <class T>
struct A { typedef int Bar; };
And this call:
int a;
foo(a);
What is T
in this example? Is it int
because A<int>::Bar
is int
, OR float
because
A<float>::Bar
is int
too OR whatever you want.... The question is what function you are calling foo<int>(int)
or foo<float>(int)
or ...
Or to give example more closer to question:
template <class T>
struct Foo {
struct Bar {};
};
It seems that compiler should have no problems with resolving this:
template <class T>
void resolve(typename Foo<T>::Bar*);
But compiler even here has problems because it is not sure if specialization of some other class will not use inner struct of other class, like this:
template <class T>
struct Foo<T*> {
typedef Foo<T>::Bar Bar;
};
So for:
Foo<void>::Bar b;
resolve(&b);
Compiler has no chance to know which version to call:
resolve<void>(Foo<void>::Bar*);
// or
resolve<void*>(Foo<void>::Bar*);
// ^
What can I advice you - use inline friend - but implement it with some other template class. This works - but I am sure this is a little over-engineered:
template <class S>
class ImplementSwap;
template <typename T>
class Foo {
public:
struct Bar {
int a;
Bar() {}
~Bar() {}
friend class ImplementSwap<Foo<T>>;
friend void swap(Foo<T>::Bar& b1, Foo<T>::Bar& b2)
{ ImplementSwap<Foo<T>>::doSwap(b1, b2); }
Bar(Bar&& b) { swap(*this, b); }
};
};
template <class T>
class ImplementSwap<Foo<T>> {
public:
static void doSwap(typename Foo<T>::Bar&,typename Foo<T>::Bar&);
};
template <class T>
void ImplementSwap<Foo<T>>::doSwap(typename Foo<T>::Bar&,typename Foo<T>::Bar&)
{
// this one is not inline....
}
I made Bar public to do this test:
Foo<int>::Bar a = Foo<int>::Bar(); // move constructor
int main() {
swap(a,a); // explicit swap
}
[OLD]
My previous answer was completely wrong, and first comments refer to it.
friend void swap<>(typename Foo<T>::Bar&, typename Foo<T>::Bar&);
// ^^
[/OLD]
这篇关于如何显式实例化一个模板类,它有一个具有友元函数(C ++)的嵌套类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!