【发布时间】:2012-10-31 14:57:56
【问题描述】:
我最近在尝试使用完美的转发构造函数实现类层次结构时遇到了一个问题。 考虑以下示例:
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>::basic_string(const std::basic_string<_elem> &)' : 无法将参数 1 从 'const Test' 转换为'const std::basic_string<_elem> &'
我的理解是编译器将完美的转发构造函数视为比复制构造函数更好的数学。参见例如Scott Meyers: Copying Constructors in C++11 。在其他没有类层次结构的实现中,我可以通过 SFINAE 禁用完美转发构造函数作为复制构造函数。参见例如Martinho Fernandes: Some pitfalls with forwarding constructors。当我尝试将上述解决方案应用于此示例时,我仍然无法使用相同的错误消息进行编译。
我认为一种可能的解决方案是避免完美转发,在构造函数中按值获取参数,而不是从它们转移到类变量。
所以我的问题是,是否有其他解决方案可以解决这个问题,或者在这种情况下无法完美转发?
更新: 原来我的问题很容易被误解。所以我会试着澄清一下我的意图和背景。
- 代码是完整的,就像问题中发布的一样。没有创建其他对象或调用函数。尝试编译发布的示例时出现错误。
- 拥有完美转发构造函数的目的是为了成员初始化,而不是拥有某种额外的复制构造函数。这里的原因是在使用临时对象初始化成员时保存一些对象副本(正如 Scott Meyers 在会谈中提出的那样)
- 不幸的是,完美的转发构造函数可能与其他重载构造函数(在本示例中为复制构造函数)发生冲突。
- 就像这个问题的答案和 cmets 建议的那样:这里可能的解决方案是引入显式强制转换或使用单独的非模板构造函数(即,关于具有两个参数分别为
const string&和string&&的构造函数的示例)。
【问题讨论】:
-
可能是您写了
std::string(test)而不是std::string(test.s)之类的东西?请告诉我们 main.cc 的第 130 行 -
你写的是
s(std::forward<T>(t))而不是s(std::forward<T>(t).s)。 -
混合重载和转发模板通常是个坏主意。我会从
string创建一个构造函数并添加一个转发make_testfunction 模板。 -
@Andrey 抱歉,我应该突出显示错误消息的来源。 main.cc 中的第 130 行指的是 TestBase 中的完美转发构造函数。我将编辑我的示例...
-
@avakar 参数 t 不应是 Test 类的对象,而是某种字符串(即 std::string 或 cont char*)。我不希望完美的转发构造函数成为复制构造函数,所以我认为我不应该添加
.s
标签: c++ c++11 copy-constructor sfinae perfect-forwarding