编译时,以下代码会导致此错误:
'Container::Wrapper::Wrapper(S)': member function already defined or declared
编译器是否认为Wrapper
的构造函数中的S&&
是转发引用?
template<typename T>
struct Container
{
template<class S>
struct Wrapper {
S obj;
Wrapper(S&& obj) : obj(std::forward<S>(obj)){}
Wrapper(const S& obj) : obj(obj){}
};
template<class S>
void push_back(S&& obj) {
void *storage = malloc(sizeof(Wrapper<S>));
new (storage) Wrapper<S>(std::forward<S>(obj));
}
};
struct Foobar{};
int main()
{
Container<Foobar> cont;
Foobar foobar;
cont.push_back(foobar);
return 0;
}
查看 here 中的示例,我不明白我在做什么有什么不同:
template <class T, class Allocator = allocator<T> >
class vector {
public:
...
void push_back(T&& x); // fully specified parameter type ⇒ no type deduction;
... // && ≡ rvalue reference
};
编辑:
此问题的解决方案是修改 push_back
以从用于实例化 Wrapper
的类型中删除引用:
template<class S>
void push_back(S&& obj) {
typedef std::remove_reference<S>::type U;
void *storage = malloc(sizeof(Wrapper<U>));
new (storage) Wrapper<U>(std::forward<S>(obj));
}
最佳答案
Wrapper
的实现没有涉及通用引用。 .您代码中唯一的通用引用是 Container<>::push_back
的参数。
当您调用 cont.push_back(foobar);
时, 参数 S
的 push_back
推导为 Foobar &
.
稍后您尝试实例化您的 Wrapper<S>
与 S == Foobar &
.引用折叠规则规定在 Wrapper
的构造函数参数声明 S &&
变成 Foobar &
和 const S &
也变成了Foobar &
.
这意味着您最终得到两个所谓的“重载”Wrapper::Wrapper
具有相同签名的构造函数。这就是您观察到的错误消息的原因。
如果您尝试实例化 std::vector
使用左值引用类型的模板参数,您将遇到与它的 push_back
完全相同的问题。过载。然而,在达到 push_back
之前,这样的尝试编译通常会由于其他原因而惨败。过载。
一个更精炼的例子如下所示
template <typename T> struct MyVector {
void foo(T &&) {}
void foo(const T &) {}
};
int main() {
MyVector<int &> v;
}
并且会产生同样的错误。
这里相当不明显的部分是 const T &
与 T = U &
实际上变成了U &
而不是 const U &
.但事实确实如此。
关于c++ - && 什么时候表示 'forwarding reference' ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41250100/