请考虑以下示例:
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) {} };
Error 3 error C2664: ‘std::basic_string<_Elem,_Traits,_Alloc>::basic_string(const std::basic_string<_Elem,_Alloc> &)’ : cannot convert parameter 1 from ‘const Test’ to ‘const std::basic_string<_Elem,_Alloc> &’
我的理解是编译器将完美的转发构造函数视为比复制构造函数更好的数学运算.例如,参见Scott Meyers: Copying Constructors in C++11 .在没有类层次结构的其他实现中,我可以通过SFINAE禁用完美转发构造函数作为复制构造函数.请参阅例如Martinho Fernandes: Some pitfalls with forwarding constructors.当我尝试将上述解决方案应用于此示例时,我仍然无法使用相同的错误消息进行编译.
我认为一种可能的解决方案是避免完美转发,在构造函数中按值获取参数,然后从它们移动到类变量.
所以我的问题是,如果这个问题有其他一些解决方案,或者在这种情况下不可能完美转发?
更新:
事实证明,我的问题很容易被误解.所以我会尝试澄清我的意图和背景.
>代码完整,就像发布在问题中一样.没有创建其他对象或调用函数.尝试编译发布的示例时出现错误.
>拥有完美的转发构造函数的目的是成员初始化,而不是拥有某种额外的复制构造函数.这里的原因是在使用临时对象初始化成员时保存一些对象副本(正如Scott Meyers在会谈中提出的那样)
>不幸的是,事实证明,完美的转发构造函数可能会与其他重载的构造函数冲突(在此示例中使用复制构造函数).
>类似于对这个问题的答案和评论建议:这里可能的解决方案是引入显式强制转换或具有单独的非模板化构造函数(即,关于具有两个构造函数的示例,其中参数为const string&和&&&&&&&&
解决方法
第二个Test构造函数调用TestBase,有两种可能性.其中一个需要任何东西,另一个需要一个TestBase.但是你正在通过测试 – “任何事情”都会更好地匹配.通过显式地转换为TestBase const&,我们应该能够得到正确的匹配.
另一种可能性可能涉及如何构造Test – 也许你传递的是将模板构造函数与Test相匹配?我们可以通过从Test中删除模板构造函数并查看错误是否消失来测试另一种可能性.