可变模板构造函数和复制构造函数

Variadic template constructor and copy constructor

本文关键字:构造函数 复制      更新时间:2023-10-16

我不明白为什么编译器选择我的Production类的复制构造函数,而没有其他候选函数。我做了一个最小的例子来证明这个错误:

#include <string>
#include <typeindex>
#include <iostream>
struct DummyProduction {
};
struct Dep {
};
struct Pro {
};
class ModuleBase {
};
template<typename Production = DummyProduction>
class Provider {
public:
  template<typename... Dependencies>
  Provider(ModuleBase& module, Dependencies... args)
  {
    std::cout << "Provider called!" << std::endl;
  }
  Provider(const Provider&) = delete;
};
class TargetController : public ModuleBase,
  public Provider<Pro>,
  public Provider<>
{
public:
  TargetController();
private:
  Dep p;
};
TargetController::TargetController() :
  ModuleBase(),
  Provider<Pro>(*this, &p),
  Provider<>(*this),
  p()
{
}
int main()
{
  TargetController x;
  return 0;
}

我试过gcc和clang。这里有一个链接到不起作用的例子:链接。

对于Provider<Pro>(*this, p),调用正确的构造函数。但是对于第二个例子Provider<>(*this),编译器试图调用复制构造函数。

根据我从重载解析页面了解到的内容,所有与表达式匹配的函数都应该进入候选函数集。但是,变量构造函数不在没有依赖项的提供程序的集合内,或者编译器选择了复制构造函数,尽管它被删除了。

有没有办法避免这种行为?

函数/方法是deleted这一事实并没有将其从重载列表中删除。复制构造函数的优先级高于模板方法(因为它不是完全匹配的)。

作为变通方法,您可以将其转换为预期类型:

TargetController::TargetController() :
  ModuleBase(),
  Provider<Pro>(*this, p),
  Provider<>(static_cast<ModuleBase&>(*this))
{
}

演示

模板化构造函数永远不是复制构造函数。当您调用基的构造函数并将对基(或派生)的引用传递给它时,应该调用复制构造函数。该模板在该上下文中不是一个选项。

Provider<>(*this)

就是这样一个语境。

值得注意的是,我相信VS仍然犯了这个错误。在那个编译器中,你必须转换为base&否则它将调用模板。