我最近在尝试使用完美的转发构造函数实现类层次结构时遇到了一个问题。考虑以下示例:
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) {}
};
当我尝试编译代码时,出现以下错误:
错误 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: Copying Constructors in C++11。在其他没有类层次结构的实现中,我可以通过 SFINAE 禁用完美转发构造函数作为复制构造函数。例如,参见Martinho Fernandes:转发构造函数的一些陷阱。当我尝试将上述解决方案应用于此示例时,我仍然无法使用相同的错误消息进行编译。
我认为一种可能的解决方案是避免完美转发,在构造函数中按值获取参数,而不是从它们移动到类变量。
所以我的问题是这个问题是否有其他解决方案,或者在这种情况下是否不可能完美转发?
更新: 原来我的问题很容易被误解。所以我会试着澄清一下我的意图和背景。
- 代码是完整的,就像问题中发布的一样。没有创建其他对象或调用函数。尝试编译发布的示例时出现错误。
- 拥有完美的转发构造函数的目的是用于成员初始化,而不是拥有某种额外的复制构造函数。这里的原因是在使用临时对象初始化成员时保存一些对象副本(正如 Scott Meyers 在会谈中提出的那样)
- 不幸的是,事实证明,完美的转发构造函数可能与其他重载的构造函数发生冲突(在此示例中为复制构造函数)。
- 就像建议的这个问题的答案和评论一样:这里可能的解决方案是引入显式强制转换或具有单独的非模板构造函数(即,关于具有两个分别带有参数
const string&
和的构造函数的示例string&&
)。