如何显式实例化一个具有嵌套类的模板类和一个朋友的函数(C)

前端之家收集整理的这篇文章主要介绍了如何显式实例化一个具有嵌套类的模板类和一个朋友的函数(C)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
可能以前被问过,但是这一切都接近了我对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

但是如何在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 = 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’

我猜,当显式实例化Foo时,还需要创建交换代码,这是有道理的,但为什么编译器不能确定需要创建交换(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 = 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,但我不明白答案.为什么不能在其声明之外定义掉交换?就我(mis)理解的东西而言,为什么编译器不能为代理创建交换代码(Foo< int> :: Bar& …)并链接代码中,以便显式实例化Foo< int>?我完全误解了发生了什么吗?有什么问题?

更新3

好的,这不能做,因为如果有模板专长,编译器不能保证在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<T>::Bar& b2) {}

//template class Foo<int>; // let's comment this explicit instantiation out.

代码编译好(g 4.7.1,flags:-Wall -std = c 11).但是,不应该警告我这个代码可能会导致问题吗?当我添加Foo的显式实例化时,问题不在于该行本身,而是在Foo之外实现了交换代码.

解决方法

问题不在于朋友.

问题是这个函数本身:

template <typename T>
void swap(typename Foo<T>::Bar& b1,typename Foo<T>::Bar& b2) {} // line 26

从嵌套类推导模板参数T是不可能的,请参阅:Output a nested class inside a template甚至更好的答案:https://stackoverflow.com/a/4092248/1463922

为了给出示例,为什么不能做,考虑这个功能

template <class T>
void foo(typename A<T>::Bar);

而这个A定义:

template <class T>
struct A { typedef int Bar; };

而这个电话:

int a;
foo(a);

在这个例子中是什么T?它是int,因为A< int> :: Bar是int,或是因为浮动
A< float> :: Bar是int或者任何你想要的… ….问题是你调用foo< int>(int)或foo< float>(int)或…

或者给出更接近问题的例子:

template <class T>
struct Foo {
   struct Bar {}; 
};

看来编译器在解决这个问题上应该没有问题:

template <class T>
void resolve(typename Foo<T>::Bar*);

但编译器甚至在这里也有问题,因为不确定某个其他类的特殊化是否不会使用其他类的内部结构,如下所示:

template <class T>
struct Foo<T*> {
   typedef Foo<T>::Bar Bar; 
};

因此对于:

Foo<void>::Bar b;
resolve(&b);

编译器没有机会知道要调用哪个版本:

resolve<void>(Foo<void>::Bar*);
// or 
resolve<void*>(Foo<void>::Bar*);
//          ^

我可以建议你 – 使用内联的朋友 – 但实现它与一些其他模板类.这样做 – 但我相信这有点过度设计:

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....
}

我让酒吧公开做这个测试:

Foo<int>::Bar a = Foo<int>::Bar(); // move constructor

int main() {
  swap(a,a); // explicit swap
}

[旧]
我以前的答案是完全错误的,第一个评论是指的.

friend void swap<>(typename Foo<T>::Bar&,typename Foo<T>::Bar&);
//       ^^

[/旧]

猜你在找的C&C++相关文章