使用 Auto 时在派生 class 中使用虚拟析构函数强制复制构造函数

Forced copy constructor in derived class with virtual destructor when using Auto

我试图推导 std::unique_lock 并且我 运行 解决了一个我无法用更简单的 class 复制的问题。下面是复制问题的可编译代码:

#include <iostream>
#include <mutex>
#include <string>

template<class T>
class A : public std::unique_lock<T>
{
 public:
  template<typename... Args>
  A(const std::string name, Args&&... args) : name_(name), 
  std::unique_lock<T>(args...) { }
  virtual ~A() {}  // if this destructor exists...
  private:
  std::string name_;
};


int main()
{
  std::timed_mutex tm;
  auto a = A<std::timed_mutex>("Hello", tm, std::defer_lock); // this line fails
  A<std::timed_mutex> a("Hello", tm, std::defer_lock); // this line works
  return 0;
}

如果虚拟析构函数存在(我实际 class 需要它),那么我不能使用带有 auto 的行来实例化 class 因为最终 std::unique_lock 中的构造函数被调用的是删除的那个,它带有一个被删除的 const T& 互斥锁(b/c 锁 class 无法处理 const 互斥锁)。我假设它的调用删除了 const ctor,因为出于某种原因,它调用 A() 中的复制构造函数,该构造函数将 const &A 作为输入(根据下面的错误日志)。如果我只是使用非自动样式实例化代码(已标记),那么它编译得很好。

我正在使用 gcc 5.4.1 设置(CMAKE_CXX_STANDARD 11)设置。我也试过 14 和 17,所以我假设它不是我正在使用的 cpp。

如果您的 class 包含 user-declared 析构函数、copy-constructor 或赋值运算符,编译器将不会隐式生成 move-constructor。由于 A 没有 move-constructor,编译器回退到 copy-constructor,它被隐式删除,因为 std::unique_lock 的 copy-constructor 被删除。

您可以显式声明一个 move-constructor 来让事情正常进行:

template<class T>
class A : public std::unique_lock<T>
{
public:
  template<typename... Args>
  A(const std::string name, Args&&... args)
    : std::unique_lock<T>(args...),
      name_(name)
  { }
  A(A&&) = default;
  virtual ~A() {}
private:
  std::string name_;
};

Live example

您可能还应该声明一个 move-assignment 运算符,但在这种情况下没有必要。