如何显式实例化一个模板类,它有一个具有友元函数(C ++)的嵌套类 [英] How to explicitly instantiate a template class that has a nested class with a friend function (C++)

查看:156
本文介绍了如何显式实例化一个模板类,它有一个具有友元函数(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 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆