我最近像这样使用reference_wrapper
:
#include <iostream>
#include <vector>
#include <functional>
#include <memory>
struct A {
};
struct B {
B() {};
B(A& aA) {};
B(const B&) = default;
};
int main () {
A a;
B b;
std::vector<std::reference_wrapper<B>> rvector;
rvector.push_back(std::reference_wrapper<B>(b)); // (1)
rvector.push_back(b); // (2)
1和2都可以正常编译和工作,我想知道哪一个是正确的!所以我认为以下方法也可以工作:
std::vector<B> bvector;
bvector.push_back(a); // (3)
bvector.push_back(b); // (4)
std::cout << bvector.size() << "\n";
是的,它有效!因此,我得出的结论是,push_back
仅使用给定参数调用类型的T
构造函数。尽管Documentation提到参数的类型为T
,最后是复制/移动ctor类型。
当我使用shared_ptr
尝试1和2时:
std::vector<std::shared_ptr<B>> pvector;
pvector.push_back(std::shared_ptr<B>(new B())); // (5)
pvector.push_back(new B()); // (6)
我明白了
no matching function for call to 'std::vector<std::shared_ptr<B> >::push_back(B*)'
shared_ptr<B>
作为参数的B*
构造函数,不是吗?那么,为什么6不编译(因为3编译)?emplace_back
而已,那么这不是一个坏方法)吗?答案 0 :(得分:1)
Constructor of std::reference_wrapper
是converting constructor,它允许从B
到std::reference_wrapper<B>
的隐式转换,这就是(2)起作用的原因。
但是constructor (3) of std::shared_ptr
是explicit
,因此您必须在(5)中明确指定std::shared_ptr<B>
。
答案 1 :(得分:1)
为什么2甚至3可以工作但6不能工作?
std::vector::push_back
以T
作为参数,如果您传递的内容可以隐式转换为T
,则它将起作用。
(2)之所以有效,是因为B
可以隐式转换为std::reference_wrapper<B>
。 (3)之所以有效,是因为A
可以隐式转换为B
。 (6)不起作用,因为B*
无法隐式转换为shared_ptr<B>
。请注意,the constructor of shared_ptr
taking raw pointers被标记为explicit
。
由于3可以编译并正常工作,因此可以使用它并依靠它吗(如果因为有emplace_back,这不是一个坏方法)?
是的,您可以使用它,但是请注意,emplace_back
有时更有效;它将直接在原位构造元素而不进行任何隐式转换,而不是构造临时T
并将其移动到vector
中(作为push_back
)。
答案 2 :(得分:1)
push_back
取T const&
或T&&
。
因此,如果我们有一个vector<X>
,则push_back(expr)
可以在X const& x=expr;
或X&& x=expr;
进行编译的情况下工作,并且匹配性更好,移动/复制也不是模棱两可允许使用自变量。
那些是为您的第一种情况编译的,但不是从ptr共享的ptr,因为X x=expr;
不会调用explicit
构造函数。
如果要考虑使用显式构造函数,则可以vec.emplace_back(expr)
。