类层次结构中完美转发构造函数和复制构造函数之间的冲突

mkh*_*mkh 7 c++ copy-constructor sfinae perfect-forwarding c++11

我最近在尝试使用完美的转发构造函数实现类层次结构时遇到了问题.请考虑以下示例:

struct TestBase {
  template<typename T>
  explicit TestBase(T&& t) : s(std::forward<T>(t)) {} // Compiler refers to this line in the error message

  TestBase(const TestBase& other) : s(other.s) {}

  std::string s;
};

struct Test : public TestBase {
  template<typename T>
  explicit Test(T&& t) : TestBase(std::forward<T>(t)) {}

  Test(const Test& other) : TestBase(other) {}
};
Run Code Online (Sandbox Code Playgroud)

当我尝试编译代码时,我收到以下错误:

错误3错误C2664:'std :: basic_string <_Elem,_Traits,_Alloc> :: basic_string(const std :: basic_string <_Elem,_Traits,_Alloc>&)':无法将参数1从'const Test'转换为'const std :: basic_string <_Elem,_Traits,_Alloc>&'

我的理解是编译器将完美的转发构造函数视为比复制构造函数更好的数学.例如,参见Scott Meyers:C++ 11中的复制构造函数.在没有类层次结构的其他实现中,我可以通过SFINAE禁用完美转发构造函数作为复制构造函数.例如,参见Martinho Fernandes:转发构造函数的一些缺陷.当我尝试将上述解决方案应用于此示例时,我仍然无法使用相同的错误消息进行编译.

我认为一种可能的解决方案是避免完美转发,在构造函数中按值获取参数,然后从它们移动到类变量.

所以我的问题是,如果这个问题有其他一些解决方案,或者在这种情况下是否完全转发?

更新: 原来我的问题很容易被误解.所以我会尝试澄清我的意图和背景.

  • 代码是完整的,就像发布在问题中一样.没有创建其他对象或调用函数.尝试编译发布的示例时出现错误.
  • 拥有完美转发构造函数的目的是成员初始化,而不是拥有某种额外的复制构造函数.这里的原因是在使用临时对象初始化成员时保存一些对象副本(正如Scott Meyers在会谈中提出的那样)
  • 不幸的是,事实证明,完美的转发构造函数可能会与其他重载的构造函数冲突(在此示例中使用复制构造函数).
  • 类似的答案和评论对这个问题建议:可能的解决方案在这里将引入显式转换或具有独立的非模板的构造函数(即对于具有两个构造带参数的例子const string&,并string&&分别).

Yak*_*ont 2

尝试更改Test(const Test& other) : TestBase(other) {}Test(const Test& other) : TestBase(static_cast<TestBase const&>(other)) {}

第二个Test构造函数正在调用 TestBase,有两种可能性。其中一个接受任何东西,另一个接受测试库。但你正在向它传递一个测试——“任何东西”都匹配得更好。通过显式转换为 TestBase const&,我们应该能够获得正确的匹配。

另一种可能性可能涉及 Test 的构造方式——也许您传入的内容与 Test 的模板构造函数相匹配?我们可以通过从测试中删除模板构造函数来测试另一种可能性,并查看错误是否消失。

如果是这种情况,为什么您链接的技术(在推导的类型与 Test 匹配时禁用 Test 模板构造函数)不起作用?