我有一个这样的模板:
template<typename T>
struct foo {
T m_t;
foo(T t) : m_t(t) {}
};
问题是我想同时支持小型/常规类型和大型类型(如矩阵)T
。你推荐我这样写构造函数初始化列表吗
foo (T t) : m_t(std::move(t)) {}
并要求该类型T
始终支持移动构造,即使对于较小的类型?有没有更好的方法?
我有一个这样的模板:
template<typename T>
struct foo {
T m_t;
foo(T t) : m_t(t) {}
};
问题是我想同时支持小型/常规类型和大型类型(如矩阵)T
。你推荐我这样写构造函数初始化列表吗
foo (T t) : m_t(std::move(t)) {}
并要求该类型T
始终支持移动构造,即使对于较小的类型?有没有更好的方法?
并要求类型 T 始终支持移动构造,即使对于较小的类型?
任何可复制构造的类型也是可移动构造的。在这些情况下移动只需调用复制构造函数。因此,没有理由不使用m_t(std::move(t))
.
另一种方法是使用引用:
foo (T const& t) : m_t(t) {}
foo (T&& t) : m_t(std::move(t)) {}
这样做的好处是只涉及一种构造而不是两种构造。
Yes, using the move has no disadvantage in that situation. All copyable objects are automatically moveable, so it doesn't matter. In fact, some recommend to always move variables when possible, even integers.
As an alternative, you may consider to use perfect forwarding, as described in this answer:
template <typename T2>
foo(T2&& t) : m_t(std::forward<T2>(t)) {}
If you know that T
defines a fast move constructor, it should not matter. Otherwise, providing a constructor foo(const T&)
is recommended to avoid unnecessary copies.
Perfect forwarding is only one technique to achieve that. The solution of Pubby to write out the constructor foo(const T&)
and foo(T&&)
is, of course, also fine. The results are the same, it is mostly a matter of style.
You also asked about small integer types. In theory, passing them by reference is slower than copying them, but the compiler should be able to optimize it to a copy, anyway. I don't think it will make a difference.
So, better optimize for the worst case where T
can be huge and does not provide a fast move constructor. Passing by reference is best for that situation and should not be a bad choice in general, either.
按值传递的优点是只有一个构造函数(没有模板),但与上述替代方案相比,它的代价是增加了一个移动构造。
但是,Pubby 给出的按值传递和非模板解决方案还有一个尚未提及的缺点:如果将复制构造函数定义为,则移动将不起作用T(T&);
(注意对非常量的引用)。Rvalue-references 可以绑定到 lvalue-references-to-const,但不能绑定到 lvalue-references-to-non-const,因此编译器不能调用复制构造函数。
要解决此问题,您只需foo (T & t) : m_t(t) {}
在 Pubby 的解决方案中添加第三个重载即可。