编译时,以下代码会导致此错误:
'Container :: Wrapper :: Wrapper(S)':已经是成员函数 定义或声明
编译器是否认为S&&
的构造函数中的Wrapper
是转发引用?
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));
}
答案 0 :(得分:2)
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 &
。但情况确实如此。