足够简单的代码,其中 bar
有一个 foo
类型的成员:
struct foo {
foo(int some, int parameters) {}
};
struct bar {
foo f;
bar(foo f_) { f = f_; }
}
如何更改它以便 bar
可以仅用 foo
“就地”初始化,例如像这样?
foo f;
bar b1(f); //error
bar b2(1,2); //works!
目的是有时我正在处理无法复制的类 foo
,这样做会使意图清晰。
最佳答案
正如@KerrekSB 提到的,最简单的方法是复制 foo
在 bar
中的构造函数:
bar(int a, int b) : f(a, b) {}
然而,当 foo
时,这很快就变得不切实际了。有大量的构造函数,如果 bar
甚至可能是不可能的是 template<typename T>
并且您想对任何可能的 T
执行此操作.
进入C++11的完美转发:
template<typename... Args>
bar(Args&&... args) : f(std::forward<Args>(args)...) {}
这允许您的 bar
构造函数将它接收到的任何参数直接转发给 foo
构造函数,就像 emplace
C++11 标准库中的方法。
现在还有一个问题:因为你的 bar
构造函数接受您的 foo
的任何 参数构造函数接受,显然如果 foo
然后有一个复制构造函数 bar
会接受它:
bar b1(1, 2); // ok
foo f(1, 2);
bar b2(f); // ok too!
诀窍是删除相关的构造函数:
struct bar {
foo f;
template<typename... Args>
bar(Args&&... args) : f(std::forward<Args>(args)...) {}
bar(const foo&) = delete;
bar(foo&) = delete;
};
foo f(1, 2);
bar b2(f); // error: use of deleted function ‘bar::bar(foo&)’
请注意,我故意没有删除移动构造函数,因为我假设您禁用复制的动机是性能。这样你仍然可以写:
foo f(1, 2);
bar b1(std::move(f)); // move: ok
bar b2(foo(1, 2)); // temporary: ok (it is really moved)
当然,如果你也想删除移动构造函数,那非常简单:
struct bar {
foo f;
template<typename... Args>
bar(Args&&... args) : f(std::forward<Args>(args)...) {}
bar(const foo&) = delete;
bar(foo&) = delete;
bar(foo&&) = delete;
};
foo f(1, 2);
bar b1(std::move(f)); // error: use of deleted function ‘bar::bar(foo&&)’
bar b2(foo(1, 2)); // error: use of deleted function ‘bar::bar(foo&&)’
特质:我不知道为什么,但即使在 bar
中删除了移动构造函数, 它仍然接受默认构造的临时 (GCC 4.7):
bar b3(foo()); // WTH, this works
我错过一定有充分的理由,但我不知道这里到底发生了什么。如果有人能阐明这一点......
关于c++ - 强制 "in-place" build ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16726378/