【问题标题】:Swap function for user-defined class never instantiated?从未实例化用户定义类的交换函数?
【发布时间】:2016-02-06 00:41:06
【问题描述】:

以下是我在创建一个更大的类并尝试通过提供我自己的非成员朋友交换功能来实现 Swappable 时遇到的一个简化示例。

#include <iostream>
#include <utility>

template<typename T>
class Wrapper {
  friend void swap(Wrapper& a, Wrapper& b);

public:
  Wrapper(T t) : value_(t) {}
  const T& operator*() const { return value_; }

private:
  T value_;
};

template<typename T>
void swap(Wrapper<T>& a, Wrapper<T>& b) {
  using std::swap;
  swap(a.value_, b.value_);
}

int main() {
  Wrapper<int> w1{5}, w2{10};
  std::cout << *w1 << " " << *w2 << std::endl;
  swap(w1, w2);
  std::cout << *w1 << " " << *w2 << std::endl;
}

尝试编译这个小型测试程序会导致来自 clang 的以下链接器错误(Apple LLVM 版本 7.0.2,OS X El Capitan 10.11.3 上的 clang-700.1.81):

[~/Development/c++_test][16:30:57]$ clang++ --std=c++11 -o SwapTest SwapTest.cc
Undefined symbols for architecture x86_64:
  "swap(Wrapper<int>&, Wrapper<int>&)", referenced from:
      _main in SwapTest-a978ea.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

为什么我定义的 Wrapper 类的模板交换函数没有正确实例化,尽管我在 main() 中使用了它?

【问题讨论】:

  • 您需要先将swap 声明为模板,然后再将其声明为友元函数(template &lt;typename T&gt; void swap(Wrapper&lt;T&gt;&amp;, Wrapper&lt;T&gt;&amp;)。当然,这也意味着在 that 声明之前声明 Wrapper,因为您将它们作为参数类型。

标签: c++ templates c++11 instantiation swap


【解决方案1】:
friend void swap(Wrapper& a, Wrapper& b);

声明一个非模板函数swap,它恰好采用Wrapper&lt;T&gt;&amp; 参数。这与您的模板函数swap&lt;T&gt; 不匹配。

一个简单的解决方法是将朋友声明为模板函数。

template <typename U>
friend void swap(Wrapper<U>&a, Wrapper<U>& b);

缺点是你的朋友比你想要的多一点:每个swap 实例化都是每个Wrapper&lt;T&gt; 的朋友,而不仅仅是正确的Wrapper&lt;T&gt; 类。

更正确的方法是在类之前声明模板函数:

template <class T> class Wrapper;
template <class T>
void swap(Wrapper<T>&, Wrapper<T>&);

template <class T>
class Wrapper
{
    friend void swap<>(Wrapper&, Wrapper&);
    // ...

【讨论】:

  • 感谢您提供完整的答案,尤其是“快速”修复,然后是更正确的修复,避免不必要的交友。显然,这触及了我仍然不满意的模板细节;我错误地认为友元函数 swap 也是模板声明,因为它在模板类中,但现在它不是。
  • 或者在类定义中定义非模板友元,避免污染命名空间。
【解决方案2】:

只需将您的朋友声明更改为模板:

template<typename T>
class Wrapper {
  template<typename U>
  friend void swap(Wrapper<U>& a, Wrapper<U>& b);
  ...

gcc 在尝试编译代码时会输出一个警告

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多